How to fwrite to pointer of pointer? - c

I have a function which should store content of a file to pointer of pointer - content. When I am trying to check the result of fwrite function - it returns nothing to writn. What am I doing wrong here? Did I allocate memory correctly (if I want to copy the whole file)?
bool load(FILE* file, BYTE** content, size_t* length)
{
int len = 0, writn = 0;
fseek(file, 0, SEEK_END);
*length = len = ftell(file);
rewind(file);
*content = (char) malloc((len + 1) * sizeof(char)); //(len + 1) * sizeof(char)
writn = fwrite(*content, len + 1, 1, file);
return true;
}

You probably opened the file for reading "r" mode and fwrite() will write into the file, not read. If this is the case fwrite() will fail of course.
Perhaps you simply need
// Use long int for `length' to avoid a problem with `ftell()'
// read the documentation
bool load(FILE* file, BYTE **content, long int *length)
{
fseek(file, 0, SEEK_END);
*length = ftell(file);
rewind(file);
if (*length == -1)
return false;
*content = malloc(*length + 1);
if (*content == NULL)
return false;
if (fread(*content, 1, *length, file) != *length) {
free(*content);
*content = NULL;
return false;
}
(*content)[*length] = '\0';
return true;
}
You also, try to "read" more data than available, since you get the file length and still try to read 1 more byte.

What I see this function do is:
determine the size of the file;
allocate a chunk of memory that size;
write that chunk to the file.
This assumes that file is opened for reading and writing. The fseek seeks to the end of the file (a read operation); following the rewind the chunk is written (write operation). If the file is only opened for writing, then fseek will probably fail, so your size will be zero. If the file is only open for reading, then your fwrite will fail. In addition, tou write uninitialized data to the file (the allocated memory has not been ininitialized).
Is this what it is supposed to do?

Related

Accurately search for all positions of a string in a large binary file in C

I'm currently working on a program that will parse a raw h264/MVC video file (which are found in 3D BluRays), and collect the depth values used to give subtitles a 3D effect.
To do this I have to search the file for a string called "OFMD", and then read the bytes that sit after that string. Since there are a lot of these OFMDs I have to repeat this for all instances within the file.
I was able to write a Python method that does this pretty well.
blockSize = 1048576
with open(fileName, 'rb') as f:
while True:
keepgoing = True
piece = f.read(blockSize)
posOFMD = piece.find(b'OFMD')
while posOFMD == -1:
piece += f.read(blockSize)
posOFMD = piece.find(b'OFMD')
if os.stat(fileName).st_size == f.tell():
keepgoing = False
break
if not keepgoing:
break
# Seek file to pos of OFMD.
f.seek(-len(piece), 1)
f.seek(posOFMD, 1)
piece = f.read(blockSize)
# Process 'piece'
# Seek file to the pos of OFMD plus 1.
f.seek(-len(piece), 1)
f.seek(1, 1)
I'd like to get this function working in C, but the problem I'm running into is that I can't figure out how to stop the loop after reaching the end-of-file while also accurately catching all "OFMD" strings.
Here's a portion of the code I've tried. The rest can be found on this Github gist.
mvcFile = fopen(fileName, "rb");
fseek(mvcFile, 0L, SEEK_END);
mvcFileSize = ftell(mvcFile);
fseek(mvcFile, 0L, SEEK_SET);
while (1) {
keepgoing = 1;
buffer = (char *)malloc(blockSize * sizeof(char));
fread(buffer, blockSize, 1, mvcFile);
size_t nbytes = blockSize;
if ((OFMDptr = my_memmem(buffer, blockSize, "OFMD", 4)) != NULL) {
posOFMD = OFMDptr - buffer;
} else {
posOFMD = -1;
}
// Until we find new posOFMD. Search more of the file.
while (posOFMD == -1) {
buffer = (char *)realloc(buffer, (blockSize + nbytes) * sizeof(char));
fread(buffer + nbytes, blockSize, 1, mvcFile);
nbytes += blockSize;
if ((OFMDptr = my_memmem(buffer, nbytes, "OFMD", 4)) != NULL) {
posOFMD = OFMDptr - buffer;
} else {
posOFMD = -1;
}
// TODO: When we reach the end of the file stop the loops.
if (feof(mvcFile)) {
keepgoing = 0;
break;
}
}
if (keepgoing == 0) {
break;
}
// Seek file to the OFMD's location
fseek(mvcFile, -(nbytes), SEEK_CUR);
fseek(mvcFile, posOFMD, SEEK_CUR);
// Load a chunk of the file starting at the position of the OFMD.
buffer = (char *)realloc(buffer, blockSize * sizeof(char));
fread(buffer, blockSize, 1, mvcFile);
// Process Data.
// Seek file to the OFMD's location plus 1 byte.
fseek(mvcFile, -(blockSize), SEEK_CUR);
fseek(mvcFile, 1, SEEK_CUR);
free(buffer);
}
}
the my_memmem function comes from here.
Any help would be appreciated.
Okay, so I rewrote my program, and managed to solve my issue.
Here's a new Github gist with my new program.
I've put my search code in a new function that moves the file pointer to the start of the string if it is found. Other wise it will return NULL.
To stop it from continuously reading the file all I needed to do was keep track of how much of the file was left. Once the number of bytes left in the file is smaller than my blockSize I would just only search for the string inside what's left of the file.
Here's a piece of code from my new function.
fileLeft = fileSize - ftell(file);
// Initialize buffer.
buffer = (char *)malloc(blockSize * sizeof(char));
fread(buffer, 1, blockSize, file);
// If we're reaching the end of the file.
// Only search the last chunk of the file.
if (fileLeft < BlockSize) {
if ((offsetPtr = my_memmem(buffer, blockSize, small, smallSize)) != NULL) {
smallPos = offsetPtr - buffer;
fseek(file, -blockSize, SEEK_CUR);
fseek(file, smallPos, SEEK_CUR);
free(buffer);
return file;
} else {
free(buffer);
return NULL;
}
}
I still need to improve the function a bit so that it doesn't continuously eat memory if it sits in that while loop for too long searching the string. Other than that I think I've figured it out.

How to read multiple .txt files into a single buffer?

I am trying to read multiple text files into a single char* array in C. I can get as far as allocating the char* to the correct size (i.e. the sizes of all the text files summed up).
I tried to read each file, one by one, into their own buffer, then concatenate that buffer onto the end of the one that contains them all. This is all done in a for-loop. But when I print it out to make sure it worked, only the last file that was read is printed out.
I have also tried fread, but that seems to overwrite the buffer that it writes to, rather than append to the end of it.
Here is my code, most of it is from another SO thread:
for(int i = 2; i < argc; i++) {
char *buffer = NULL;
size_t size = 0;
/* Get the buffer size */
fseek(file, 0, SEEK_END); /* Go to end of file */
size = ftell(file); /* How many bytes did we pass ? */
/* Set position of stream to the beginning */
rewind(file);
/* Allocate the buffer (no need to initialize it with calloc) */
buffer = malloc((size + 1) * sizeof(*buffer)); /* size + 1 byte for the \0 */
/* Read the file into the buffer */
fread(buffer, size, 1, file); /* Read 1 chunk of size bytes from fp into buffer */
/* NULL-terminate the buffer */
buffer[size] = '\0';
allFiles = strcat(allFiles, buffer);
free(buffer);
fclose(file);
}
Please help me out, I am stumped by what seems like a simple thing to do in C. Thanks.
It sounds like you're doing everything correct, but you need to increment the pointer before you pass it to fread for the next file otherwise you'll overwrite the beginning of the file over and over.
Assuming buf is the correct size for all the files +1 for the nul byte and files is an array of char *'s containing the filenames NUM_FILES long, you'll need to do something like this.
char *p = buf;
for(int i = 0; i < NUM_FILES; i++) {
FILE *f = fopen(files[i], "rb");
fseek(f, 0, SEEK_END);
long bytes = ftell(f);
fseek(f, 0, SEEK_SET);
fread(p, (size_t)bytes, 1, f);
p += bytes;
fclose(f);
}
*p = 0;

using memcmp to compare buffers with 0 bytes

I am trying to compare 2 texts from files byte by byte using memcmp, after I read both of them into memory, one file into a buffer(char* or char[], tried both). the problem is, the file I read into a buffer have a lot of 0 bytes, which makes him stop at the first 0 byte thinking it is a null terminating zero, which makes a segmentation fault. how can I make the function keep compare bytes even so there are 0 bytes?
I already tried to check if the buffer is full or not, I printed it byte by byte and it showed all of the bytes including the 0 bytes. when I print it completely using printf("%s", buffer) I get only the first byte(the second byte is 0 byte).
void detect_virus(char *buffer, unsigned int size){
link* l = (link*) malloc(sizeof(link));
load(l);
unsigned int location = 0;
while(l != NULL){
location = 0;
while(location < size - l->vir->SigSize){
int isVirus = memcmp(buffer + location, l->vir->sig, l->vir->SigSize);
if(isVirus == 0)
printf("%d, %s, %d\n", location, l->vir->virusName, l->vir->SigSize);
location++;
}
}
free(l);
}
void detect(link* list){
char filename[50];
fgets(filename, 50, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "rb");
char* buffer = (char*) malloc(10000);
fseek(file, 0, SEEK_END);
unsigned int size = ftell(file);
fseek(file, 0, SEEK_SET);
fread(buffer, 1, size, file);
detect_virus(buffer, size);
fclose(file);
}
I get a segmentation fault at the first time the memcmp function is called, instead of fully compare the texts. any ideas how to fix that?
edit
code for load function:
void load(link* list){
printf("Enter Viruses file name: \n");
char* filename = (char*) malloc(100);
fgets(filename, 100, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "r");
while(!feof(file)){
short length = 0;
fread(&length, 2, 1, file);
if(length == 0)
break;
struct virus* v = (struct virus*)malloc(length);
fseek(file, -2, SEEK_CUR);
fread(v, length, 1, file);
v->SigSize = v->SigSize - 18;
list_append(list, v);
}
list = list->nextVirus;
free(filename);
fclose(file);
}
as a note, I tested the function before and it worked.
edit
I found out the problem, thank you all!
Per 7.21.6.7 The sscanf function, paragraph 2 of the C standard (bolding mine):
The sscanf function is equivalent to fscanf, except that input is obtained from a string (specified by the argument s) rather than from a stream. Reaching the end of the string is equivalent to encountering end-of-file for the fscanf function. If copying takes place between objects that overlap, the behavior is undefined.
Note the bolded portion.
In your code:
sscanf(filename, "%s", filename);
the filename array certainly overlaps with the filename array, thus invoking undefined behavior.
Remove that line of code.
You also need to add error checking, especially checking that the return from fopen() is not NULL.

how to write one binary file to another in c

I have a few binary files that I want to write into an output file.
So I wrote this function using a char as a buffer naively thinking it would work.
//Opened hOutput for writing, hInput for reading
void faddf(FILE* hOutput, FILE* hInput) {
char c;
int scan;
do{
scan = fscanf(hInput, "%c", &c);
if (scan > 0)
fprintf(hOutput, "%c", c);
} while (scan > 0 && !feof(hInput));
}
Executing this function gives me an output of the few readable char's in the beginning binary file. So I tried it this way:
void faddf(FILE* hOutput, FILE* hInput) {
void * buffer;
int scan;
buffer = malloc(sizeof(short) * 209000000);
fread(buffer, sizeof(short), 209000000, hInput);
fwrite(buffer, sizeof(short), 209000000, hOutput);
free(buffer);
}
This "works" but is only works when the file is smaller then my "magic number" Is there a better way?
Although your new code (in the answer) is much better than the old code, it can still be improved and simplified.
Specifically, you can avoid any memory problems by copying the file in chunks.
void faddf( FILE *fpout, FILE *fpin )
{
char buffer[4096];
size_t count;
while ( (count = fread(buffer, 1, sizeof buffer, fpin)) > 0 )
fwrite(buffer, 1, count, fpout);
}
You should avoid reading bytes per byte. Use the fgets() function instead of fscanf().
Please refer to : Man fgets() (for Windows)
When you open both files next to each other (input one / output one), you're saying that the output file only contains readable characters... But can your text editor display unreadable characters on the input one ?
I should not have asked the question in the first place but here is how I ended up doing it:
void faddf(FILE* hOutput, FILE* hInput) {
void * buffer;
int scan,size;
size_t read;
//get the input file size
fseek(hInput, 0L, SEEK_END);
size = ftell(hInput);
fseek(hInput, 0L, SEEK_SET);
//place the get space
buffer = malloc(size);
if (buffer == NULL)exit(1);//should fail silently instead
//try to read everything to buffer
read = fread(buffer, 1, size, hInput);
//write what was read
fwrite(buffer, 1, read, hOutput);
//clean up
free(buffer);
}

copying contents of a text file in c

I want to read a text file and transfer it's contents to another text file in c, Here is my code:
char buffer[100];
FILE* rfile=fopen ("myfile.txt","r+");
if(rfile==NULL)
{
printf("couldn't open File...\n");
}
fseek(rfile, 0, SEEK_END);
size_t file_size = ftell(rfile);
printf("%d\n",file_size);
fseek(rfile,0,SEEK_SET);
fread(buffer,file_size,1,rfile);
FILE* pFile = fopen ( "newfile.txt" , "w+" );
fwrite (buffer , 1 ,sizeof(buffer) , pFile );
fclose(rfile);
fclose (pFile);
return 0;
}
the problem that I am facing is the appearence of unnecessary data in the receiving file,
I tried the fwrite function with both "sizeof(buffer)" and "file_size",In the first case it is displaying greater number of useless characters while in the second case the number of useless characters is only 3,I would really appreciate if someone pointed out my mistake and told me how to get rid of these useless characters...
Your are writing all the content of buffer (100 char) in the receiving file. You need to write the exact amount of data read.
fwrite(buffer, 1, file_size, pFile)
Adding more checks for your code:
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 100
int main(void) {
char buffer[BUFFER_SIZE];
size_t file_size;
size_t ret;
FILE* rfile = fopen("input.txt","r+");
if(rfile==NULL)
{
printf("couldn't open File \n");
return 0;
}
fseek(rfile, 0, SEEK_END);
file_size = ftell(rfile);
fseek(rfile,0,SEEK_SET);
printf("File size: %d\n",file_size);
if(!file_size) {
printf("Warring! Empty input file!\n");
} else if( file_size >= BUFFER_SIZE ){
printf("Warring! File size greater than %d. File will be truncated!\n", BUFFER_SIZE);
file_size = BUFFER_SIZE;
}
ret = fread(buffer, sizeof(char), file_size, rfile);
if(file_size != ret) {
printf("I/O error\n");
} else {
FILE* pFile = fopen ( "newfile.txt" , "w+" );
if(!pFile) {
printf("Can not create the destination file\n");
} else {
ret = fwrite (buffer , 1 ,file_size , pFile );
if(ret != file_size) {
printf("Writing error!");
}
fclose (pFile);
}
}
fclose(rfile);
return 0;
}
You need to check the return values from all calls to fseek(), fread() and fwrite(), even fclose().
In your example, you have fread() read 1 block which is 100 bytes long. It's often a better idea to reverse the parameters, like this: ret = fread(buffer,1,file_size,rfile). The ret value will then show how many bytes it could read, instead of just saying it could not read a full block.
Here is an implementation of an (almost) general purpose file copy function:
void fcopy(FILE *f_src, FILE *f_dst)
{
char buffer[BUFSIZ];
size_t n;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
{
if (fwrite(buffer, sizeof(char), n, f_dst) != n)
err_syserr("write failed\n");
}
}
Given an open file stream f_src to read and another open file stream f_dst to write, it copies (the remainder of) the file associated with f_src to the file associated with f_dst. It does so moderately economically, using the buffer size BUFSIZ from <stdio.h>. Often, you will find that bigger buffers (such as 4 KiB or 4096 bytes, even 64 KiB or 65536 bytes) will give better performance. Going larger than 64 KiB seldom yields much benefit, but YMMV.
The code above calls an error reporting function (err_syserr()) which is assumed not to return. That's why I designated it 'almost general purpose'. The function could be upgraded to return an int value, 0 on success and EOF on a failure:
enum { BUFFER_SIZE = 4096 };
int fcopy(FILE *f_src, FILE *f_dst)
{
char buffer[BUFFER_SIZE];
size_t n;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
{
if (fwrite(buffer, sizeof(char), n, f_dst) != n)
return EOF; // Optionally report write failure
}
if (ferror(f_src) || ferror(f_dst))
return EOF; // Optionally report I/O error detected
return 0;
}
Note that this design doesn't open or close files; it works with open file streams. You can write a wrapper that opens the files and calls the copy function (or includes the copy code into the function). Also note that to change the buffer size, I simply changed the buffer definition; I didn't change the main copy code. Also note that any 'function call overhead' in calling this little function is completely swamped by the overhead of the I/O operations themselves.
Note ftell returns a long, not a size_t. Shouldn't matter here, though. ftell itself is not necessarily a byte-offset, though. The standard requires it only to be an acceptable argument to fseek. You might get a better result from fgetpos, but it has the same portability issue from the lack of specification by the standard. (Confession: I didn't check the standard itself; got all this from the manpages.)
The more robust way to get a file-size is with fstat.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd>
struct stat stat_buf;
if (fstat(filename, &buf) == -1)
perror(filename), exit(EXIT_FAILURE);
file_size = statbuf.st_size;
I think the parameters you passed in the fwrite are not in right sequence.
To me it should be like that-
fwrite(buffer,SIZE,1,pFile)
as the syntax of fwrite is
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.
So change the sequence and try again.

Resources