Operating System Used:Ubuntu 11.04
Compiler Used: GCC
Program related files:Git Hub Link
I'm trying a implement program which will do a job, same as that of CPP (The C preprocessor) when I compile a .c file.
In this particular code Copy_file_to_buf function not copying the whole file into the buffer.
Acutal size of the is 117406C,but ftell in the copy_file_to_buf function showing it as 114689.
EDIT:
There is no data loss when I copied the contents of dummyfile to a buffer using same program but I've written copy_file_to_buf program seperately in temp.c file.
temp.c
#include<stdio.h>
main(int argc,char **argv)
{
FILE *inputFile;
int sizeofFile, rc;
char *source_buf;
fprintf(stderr, "In Copy_file_to_buf\n");
sleep(1);
inputFile=fopen(argv[1],"r");
if (!inputFile) {
fprintf(stderr, "Oops, failed to open inputfile \"%s\"\n", argv[1] );
return NULL;
}
fseek(inputFile,0,SEEK_END);
sizeofFile=ftell(inputFile);
fseek(inputFile,0,SEEK_SET);
source_buf=calloc(1,1+sizeofFile);
rc = fread(source_buf,sizeofFile,1,inputFile);
/* now check rc */
fprintf(stderr, "Size of the file=%d; fread returned %d.\n", sizeofFile, rc);
//sleep(5);
fclose(inputFile);
source_buf[sizeofFile] = 0;
puts(source_buf);
return source_buf;
}
Looks like the fseek() and ftell aren't working as expected for the below code.
puts("Copying dummyfile contents");
test_buf=Copy_file_to_buf("dummyfile");
puts(test_buf);
Filename: preprocessor.c
#include"myheader.h"
/* agrv[1]=preprocessor
* argv[2]=test.c
*
* Program on PREPROCESSOR
*
* Steps:
* 1.Removal of comments.
* 2.Inclusion of headerfiles.
* 3.Macro substitution.
* a.function like arguments
* b.Stringification
* c.Concatenation
* 4.Conditional compilation
* a.#Ifdef
* b.#If
* c.#defined
* d.#Else
* e.#Elif
*/
int
main(int argc, char *argv[])
{
char *source_buf,*subBuf,*rmc_buf,*test_buf;
char **main_header_names,**sub_header_names;
int main_header_count,sub_header_count;
source_buf=(char *)Copy_file_to_buf(argv[1]);//...
rmc_buf=removeComments(source_buf);//...
main_header_names=(char **)getMainHeaderNames(rmc_buf);//...
source_buf=(char *)Copy_file_to_buf(argv[1]);//...
rmc_buf=removeComments(source_buf);//...
main_header_count=mainHeaderCounter(rmc_buf);//...
printf("Main Header Count=%d",main_header_count);//...
includeHeaders(main_header_names,main_header_count);
subBuf=(char *)Copy_file_to_buf("pre.i");//...
sub_header_names=(char **)getSubHeadersNames(subBuf);//...
subBuf=(char *)Copy_file_to_buf("pre.i");//...
sub_header_count=subHeadersCounter(subBuf);//...
WriteSubHeadersToFile(sub_header_count,sub_header_names,"dummyfile");//...
puts("Copying dummyfile contents");
test_buf=Copy_file_to_buf("dummyfile");
puts(test_buf);
/*test_buf=removeComments(test_buf);
puts(test_buf);
sub_header_names=(char **)getSubHeadersNames(test_buf);
test_buf=(char *)Copy_file_to_buf("dummyfile");
sub_header_count=subHeadersCounter(test_buf);
WriteSubHeadersToFile(sub_header_count,sub_header_names,"dummyfile2");
printf("Line:%d File:%s",__LINE__,__FILE__);
*/
return 0;
}
Filename:CopyFile.c
#include"myheader.h"
//Copying input file data into source_buf
char * Copy_file_to_buf(char *fileName)
{
FILE *inputFile;
int sizeofFile;
char *source_buf;
puts("In Copy_file_to_buf");
inputFile=fopen(fileName,"r");
fseek(inputFile,0,2);
sizeofFile=ftell(inputFile);
sizeofFile++;
fseek(inputFile,0,0);
source_buf=calloc(1,sizeofFile);
fread(source_buf,sizeofFile,1,inputFile);
printf("SIZE OF THE FILE=%d",sizeofFile);
//sleep(5);
fclose(inputFile);
return source_buf;
}
Check the return value of fseek() (and all other library calls!)
if (fseek(inputFile, 0, SEEK_END)) perror("seek to end");
sizeofFile = ftell(inputFile);
if (sizeofFile == -1) perror("ftell");
You are asking fread to read one block sizeofFile long. If it cannot read a block that size it will fail and return zero. Instead you would do better to request sizeofFile blocks of 1 byte long. Then it will report exactly how may bytes it managed to read, which may be fewer than sizeofFile for a number of reasons.
rc = fread( source_buf, 1, sizeofFile inputFile ) ;
In your case it will always be fewer than sizeofFile because you previously incremented it, so there never were sizeofFile bytes to be read. You should have read the file size not the buffer size, but the reading multiple blocks of one byte is still preferable in any case. In fact I would suggest the following changes:
sizeofFile = ftell( inputFile ) ;
// REMOVED sizeofFile++ ;
fseek( inputFile, 0, SEEK_SET ) ;
source_buf = calloc( 1, sizeofFile + 1 ) ; // Don't confuse file size and buffer size here.
rc = fread( source_buf, 1, sizeofFile, inputFile ) ; // SWAPPED param 2 and 3
It makes sense to use a block size other than 1 if you are reading fixed length records. If reading a byte stream of arbitrary length, the size should generally be 1, and the count used to determine the amount of data read.
char * Copy_file_to_buf(char *fileName)
{
FILE *inputFile;
int sizeofFile, rc;
char *source_buf;
fprintf(stderr, "In Copy_file_to_buf\n");
inputFile=fopen(fileName,"r");
if (!inputFile) {
fprintf(stderr, "Oops, failed to open inputfile \"%s\"\n", fileName );
return NULL;
}
fseek(inputFile,0,SEEK_END);
sizeofFile=ftell(inputFile);
fseek(inputFile,0,SEEK_SET);
source_buf=calloc(1,1+sizeofFile);
rc = fread(source_buf,sizeofFile,1,inputFile);
/* now check rc */
fprintf(stderr, "SIZE OF THE FILE=%d; fread returned %d.\n", sizeofFile, rc);
//sleep(5);
fclose(inputFile);
source_buf[sizeofFile] = 0;
return source_buf;
}
UPDATE: for testing added main + includes...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
char *lutser;
lutser = Copy_file_to_buf(argv[1] );
fprintf (stderr, "Strlen(lutser)=%u\n", (unsigned) strlen(lutser) );
puts (lutser);
return 0;
}
Output:
-rw-r--r-- 1 Plasser pis 1008 2012-03-31 15:10 lutsbuf.c
-rwxr-xr-x 1 Plasser pis 8877 2012-03-31 15:11 a.out
Plasser#Pisbak$ ./a.out lutsbuf.c
In Copy_file_to_buf
SIZE OF THE FILE=1008; fread returned 1.
Strlen(lutser)=1008
...
<contents of file>
...
CopyNewFile doesn't close its file. WriteSubHeadersToFile may not always (hard to follow the flow). How are you determining the "real" size of the file?
Related
Im attempting the starts of a VM in C and i'm attempting to understand how to read out the binary file ive produced from the assembler. As per instructions of assignment we are to allocate a global memory as an unsigned byte of 1k memory space and and then using a load function are to read this binary file into the memory and then using a fetch function read these bytes into their instructions. The issue im having is part 1, how do i read this binary file into this unsigned int array and then decode it in a way that can be worked with? At the moment what i have prints out a value that isnt at all what is to be expected.
MAIN.c
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
unsigned int memory[1028];
int loads(char *filename){
FILE *file = fopen(filename, "r");
ssize_t read;
if(file == NULL){
exit(-1);
}
while(fread(&memory, sizeof(unsigned int), 1, file) == 1){
printf("%d\n", *memory);
}
fclose(file);
exit(0);
}
int main(int argc, char** argv){
if (argc <= 1){
printf("No file found\n");
return -1;
}
char *filename = argv[1];
loads(filename);
}
inputfile.txt
t#w## (this is what it shows which is unreadable but when using od -t x1 output.txt | head -5 it prints out to be 0000000 74 40 77 40 11 23
0000006)
Current Output
1081557108
Desired output
74 40 77 40 11 23
When reading with fread, fread reads bytes. It has no idea about any concept of a line. The byte '\n' (0xa) is just a byte like any other byte in the file. The declaration for fread is:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
Where ptr is the starting address for a block of memory sufficient to hold size * nmemb (size * no. of members) values from stream. Where size is the element or object size (in your case sizeof (unsigned) and nmemb is the number you will read (e.g. 1028 in the case of your unsigned memory[1028];) See man 3 fread
Where you have problems with your code is your use of &memory as the pointer. That is incorrect. (and why you get 2-values) &memory is type unsigned (*)[1028] (e.g. a pointer-to-array-of unsigned[1028]) What is the sizeof(unsigned)? (hint: 4-bytes) What is the sizeof (a_pointer)? (hint: 8-bytes on x86_64). So you are able to store 2-unsigned values in the storage of a pointer while invoking Undefined Behavior with the remainder of the read.
The correct parameter for fread is simply memory which, as an array, is converted to a pointer on access subject to the four exceptions listed in C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
In your case you declare an unsigned array memory as:
#define MAXU 1028 /* if you need a constant, #define one (or more) */
unsigned memory[MAXU];
(note: you want to avoid the use of global variables unless absolutely necessary. Instead, declare the array in the scope needed, e.g. in main() and then pass a pointer to any function where it is required)
When handling files, instead of passing a filename as a parameter to a function, instead, open the file and validate it is open in the caller (main() here), and pass an open FILE* pointer as a parameter. Unless the file can be opened, there is no need to make the function call and set up the function stack to begin with. So in main() you can do something similar to the following to pass the filename as the first argument to your program, e.g.
int main(int argc, char **argv) {
int n = 0;
if (argc < 2) { /* validate at least 1 argument given for filename */
fprintf (stderr, "usage: %s filename\n", argv[0]);
return 1; /* do NOT return negative values to the shell */
}
/* use filename provided as 1st argument */
FILE *fp = fopen (argv[1], "r");
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
(note: do NOT return a negative value to the shell. Instead return 1 or EXIT_FAILURE (which has the value 1) to indicate error)
Now you want to call your loads function passing the open file-stream fp, e.g.
if ((n = loads (fp)) == 0) { /* validate return of loads */
fputs ("error: loads() read zero bytes or error occurred.\n", stderr);
return 1;
}
Your loads() function reduces to:
int loads (FILE *fp)
{
return fread (memory, sizeof *memory, MAXU, fp);
}
(note: fread returns the number of members read, which is only equal to the number of bytes read when size == 1. So by choosing the size of unsigned it will return the number of unsigned values read).
A complete example could be:
#include <stdio.h>
#include <stdlib.h>
#define MAXU 1028 /* if you need a constant, #define one (or more) */
unsigned memory[MAXU];
int loads (FILE *fp)
{
return fread (memory, sizeof *memory, MAXU, fp);
}
int main(int argc, char **argv) {
int n = 0;
if (argc < 2) { /* validate at least 1 argument given for filename */
fprintf (stderr, "usage: %s filename\n", argv[0]);
return 1; /* do NOT return negative values to the shell */
}
/* use filename provided as 1st argument */
FILE *fp = fopen (argv[1], "r");
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if ((n = loads (fp)) == 0) { /* validate return of loads */
fputs ("error: loads() read zero bytes or error occurred.\n", stderr);
return 1;
}
for (int i = 0; i < n; i++) { /* loop n times outputting values */
if (i && i % 10 == 0) /* output 10 columns for convenience */
putchar ('\n');
printf (" %4x", memory[i] & 0xffff); /* & 0xffff is for my file */
}
putchar ('\n'); /* tidy up with newline */
}
Example Use/Output
In my file ../dat/100000int.bin I have 100,000 integer values (both positive and negative in the range of short, so I have masked the upper 2-bytes in each value with memory[i] & 0xffff to prevent the sign-extended output as an unsigned value, e.g. 0xffff7d77, when the stored values is less than zero.
$ ./bin/freadunsignedval ../dat/100000int.bin
7d77 6cad c544 21f8 723f 54d1 8a81 2c6a 1ba9 f95b
1858 7565 f4b 28e4 7fdd 5a92 b5df 7a3f 4e1a 7e19
669 f365 34c0 95e 903 689d 66f2 abf2 1223 1290
372f f9b 7f3d 71eb ce6d 717c 46bc 2712 1de6 6265
d248 363e 57cb 3d03 5f23 57a8 1795 2944 51e7 65af
275d 5851 724a 5c1e 61af 7b4d 44bb 48a2 4f5b 56de
5b32 68b 6679 5a6f 7876 180c 4beb 3f33 3f1f 69d1
2198 6cd7 200f 7963 29da 7f32 510b 4170 2877 22f3
271f 4fd4 84bc 196a 2bf2 5cf3 14b7 70ad 2595 6413
...
6503 b2 f135 15f6 776c b7f3 1ffd 1365 1e4d 129b
23f 6c3e 20c a8c 2ef6 f72b 4d4 793a 1b6b 425
79d5 6bac ba8 6527 6239 17ea 644e 1175 4464 1c88
346d 2967 1d3a 4339 3f5d 14a6 b46 5f5a
(which is 103 lines of output with 10-values per-line and 8 values in the final line)
Look things over and let me know if you have further questions.
my text file is "Foo bar!!", name foo.txt
So i want to create a new variable in my main function and copy the text file into new variable.
#include <stdio.h>
#include <stdlib.h>
FILE *fopen_with_error (const char *f, const char *mode){
FILE *fp;
if((fp = fopen(f,mode)) == NULL){
printf("Error opening %s\n",f);
exit(EXIT_FAILURE);
}
return fp;
}
int main(int argc, char* argv[]){
FILE *fp;
int a, num;
if(argc != 2){
printf("Usage: program input file\n");
return 0;
}
fp = fopen_with_error(argv[1],"rb");
}
I want to store the copied text into 'a' variable.
I tried to use fread function but everytime i try, it fails somehow.
In addition to using stat to obtain the number of bytes in the file to accurately size your buffer for reading the file into a single variable, you can also use fseek and ftell to accomplish the same thing.
The bigger issue is that you post the contents of a text file with a single-line (e.g. "Foo bar!!") and then proceed to explain you want to read the entire file into a variable. For binary input, that makes more sense. For text, you generally want to read and store individual lines rather than a file-at-once.
(you can store an entire text file line-by-line by using a pointer to pointer to char and allocating pointer and then storage for each line)
Now, don't get me wrong, you can do either, but if you need specific information from each line, and the lines differ in length, etc.., it is a whole lot easier to iterate over pointers than it is trying to scan through one giant buffer of text picking out newlines. You can think through what you need to do with the data you read from the file and make the call.
As your question is written, the basic approach is simply to open the file in binary mode, fseek forward to the end of file, use ftell to report the number of bytes in the file, allocate/validate memory to hold the file, and then read the file using fread into the allocated block of memory. (note: mmap provides another option as well)
Putting that pieces together, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
char *read_file (char* fname, size_t *nbytes)
{
long bytes = 0;
char* file_content;
FILE *file = fopen(fname, "rb");
if (!file) /* validate file open for reading */
return NULL;
fseek (file, 0, SEEK_END); /* fseek end of file */
if ((bytes = ftell (file)) == -1) { /* get number of bytes */
fprintf (stderr, "error: unable to determine file length.\n");
return NULL;
}
fseek (file, 0, SEEK_SET); /* fseek beginning of file */
/* allocate memory for file */
if (!(file_content = malloc (bytes))) { /* allocate/validate memory */
perror ("malloc - virtual memory exhausted");
return NULL;
}
/* read all data into file in single call to fread */
if (fread (file_content, 1, (size_t)bytes, file) != (size_t)bytes) {
fprintf (stderr, "error: failed to read %ld-bytes from '%s'.\n",
bytes, fname);
return NULL;
}
fclose (file); /* close file */
*nbytes = (size_t)bytes; /* update nbytes making size avialable */
return file_content; /* return pointer to caller */
}
int main (int argc, char **argv) {
size_t nbytes;
char *content;
if (argc < 2) { /* validate required argument givent */
fprintf (stderr, "error: insufficient input. filename req'd.\n");
return 1;
}
if ((content = read_file (argv[1], &nbytes))) { /* read/validate */
printf ("read %zu bytes of data from %s\n"
"------content------\n%s\n-------------------\n",
nbytes, argv[1], content);
free (content);
}
return 0;
}
Example Input File
$ cat dat/foo.txt
"Foo bar!!"
Example Use/Output
$ ./bin/freadbinfoo dat/foo.txt
read 12 bytes of data from dat/foo.txt
------content------
"Foo bar!!"
-------------------
Don't forget to use a memory use & error checking program (like valgrind on Linux) to insure there are no memory errors and that you have freed all memory you have allocated.
Here's a simple example of how to do this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
char *fname = "./someFileNameHere";
struct stat st;
stat(fname, &st);
char *content = malloc(st.st_size+1);
content[st.st_size] = 0;
FILE *infile = fopen(fname, "rb");
size_t read = fread(content, sizeof(char), st.st_size, infile);
fclose(infile);
puts(content);
return 0;
}
I've left all of the necessary error handling to you.
So I've got a project I'm working on in ANSI C (C89) for class. I've gotten stuck in the process. I'm getting a
segmentation fault: 11
issue, and no matter what I look up, I can't seem to solve the issue. can someone look at my code and point me in the right direction?
/* CS315 Lab 3: C data types */
#include <stdio.h>
#include <stdlib.h> /*added this to provide a declaration for malloc*/
#define TENMB 1048576 /*1024 kilobytes or 10 megabytes */
#define ONEB 1
FILE * fp = NULL;
End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
initialize(int argc, char ** argv)
{
/* Open the file given on the command line */
if( argc != 2 )
{
printf( "Usage: %s filename.mp3\n", argv[0] );
return(EXIT_FAILURE);
}
FILE * fp = fopen(argv[1], "rb");
if( fp == NULL )
{
printf( "Can't open file %s\n", argv[1] );
return(EXIT_FAILURE);
}
return 0; /*this might need to change */
}
readFile(FILE * fp)
{
/* How many bytes are there in the file? If you know the OS you're
on you can use a system API call to find out. Here we use ANSI
standard function calls. */
long size = 0;
fseek(fp, 0, SEEK_END ); /* go to 0 bytes from the end */
size = ftell(fp); /* how far from the beginning? */
rewind(fp); /* go back to the beginning */
if( size < ONEB || size > TENMB )
{
printf("File size is not within the allowed range\n");
End(fp); /* switched from goto END:*/
}
printf( "File size: %.2ld MB\n", size/TENMB ); /* change %d to %ld, added .2 to print to 2 decimal places (maybe use f instead) */
/* Allocate memory on the heap for a copy of the file */
unsigned char * data = (unsigned char *)malloc(size);
/* Read it into our block of memory */
size_t bytesRead = fread( data, sizeof(unsigned char), size, fp );
free(data); /* deallocation */
if( bytesRead != size )
{
printf( "Error reading file. Unexpected number of bytes read: %zu\n",bytesRead ); /* changed from %d to %zu */
End(fp); /* switched from goto END:*/
return 0;
}
return 0;
}
int main( int argc, char ** argv )
{
initialize(argc, argv);
readFile(fp);
/* We now have a pointer to the first byte of data in a copy of the file, have fun
unsigned char * data <--- this is the pointer */
}
Thanks for any help!
In your code you have declared fp twice, both globally and locally
FILE * fp = NULL;
End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
initialize(int argc, char ** argv)
{
...
FILE * fp = fopen(argv[1], "rb");
...
Even though you are writing C89 there is no need to pick up the bad things with the standard. E.g. declare functions properly with a return type.
You say that this should be C89 code, but there are some aspects of this code that are not C89 compliant. I have included a modified version of your code below that fixes these things, compiles without warnings, and seems to run correctly. By way of a disclaimer, I never write in C89, so someone else may take issue with something here.
The segfault that you report is due to the double-declaration of fp, as pointed out by #BLUEPIXY in the comments to your question. You declare this file pointer first at file scope (i.e., fp is a "global" variable), and then at block scope within the function initialize(). The second declaration hides the first one within the block, so you open a file in initialize() and assign the resulting pointer to the block scope fp (which has automatic storage duration). When main() then calls readFile(), it is the file scope fp that is passed, and this fp is initialized to NULL. So fseek(fp, 0, SEEK_END) is called on a NULL pointer, and this causes the segfault. Changing the second declaration to an assignment fixes this problem:
fp = fopen(argv[1], "rb");
You can't mix variable declarations and code in C89, so you need to move the declarations to the beginning of the functions. Also, C89 does not support the %zu format specifier for size_t variables. Instead, use %lu and cast the size_t value bytesRead to (unsigned long).
I added a definition: ONEMB 1048576, and removed the TENMB definition. In the calculation of the file size, you were dividing the number of bytes by 10MB instead of 1MB, and I take it that you were in fact trying to calculate the number of MB.
I added a check for errors to the call to ftell(). Since ftell() returns a long, I added a size_t fileSize variable and cast the value of size to size_t before assigning it to fileSize. I changed theprintf() statement to:
printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB );
so that the file size is reported with more precision; this way, files smaller than 1 MB will not be reported as having a size of 0 MB.
I removed the cast from the call to malloc(), as it is absolutely not needed in C.
The assignment to bytesRead calls fread(), which takes a size_t parameter for the third argument, not a long. You originally had the long value size here, and this is one reason for the new fileSize variable. The following line had a comparison between bytesRead, which is size_t, and size. This should generate compiler warnings (you do have them on, don't you?) as using signed and unsigned types in the same expression can lead to difficulties, and so here I used the fileSize variable again.
You were missing the return statement at the end of main(), and your function definitions were missing their return type specifiers, so I also added these. I also noticed that your program was segfaulting when invoked with no arguments. This is because on errors in your initialize() function, you were returning to the calling function, which then called readFile() with a NULL pointer. You should instead exit() from the program. I have made these changes to all file error traps in the modified code.
There are some other issues with your code. I would prefer not to use the End() function. It does not test for errors during closing files, and will segfault if you pass in a NULL pointer. Also, the "Unexpected number of bytes read" error in readFile() will end up exiting successfully, since End() always exits with EXIT_SUCCESS.
I don't love the casting from long to size_t that I did, and someone else may have a better approach. What I was trying to manage here was that ftell() returns a long, which you use to calculate the file size, and fread() both takes and returns size_t values.
Most of what I did was in the readFile() function, and I removed your comments from this function to make it easier to see what was changed.
I compiled with:
gcc -std=c89 -Wall -Wextra -pedantic
#include <stdio.h>
#include <stdlib.h> /*added this to provide a declaration for malloc*/
#define ONEMB 1048576
#define ONEB 1
FILE * fp = NULL;
void End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
int initialize(int argc, char ** argv)
{
/* Open the file given on the command line */
if( argc != 2 )
{
printf( "Usage: %s filename.mp3\n", argv[0] );
exit(EXIT_FAILURE);
}
fp = fopen(argv[1], "rb");
if( fp == NULL )
{
printf( "Can't open file %s\n", argv[1] );
exit(EXIT_FAILURE);
}
return 0; /*this might need to change */
}
int readFile(FILE * fp)
{
long size = 0;
unsigned char *data;
size_t fileSize, bytesRead;
fseek(fp, 0, SEEK_END );
if ((size = ftell(fp)) == -1) {
fprintf(stderr, "ftell() error\n");
exit(EXIT_FAILURE);
};
rewind(fp);
if( size < ONEB || size > 10 * ONEMB )
{
printf("File size is not within the allowed range\n");
End(fp);
}
fileSize = (size_t) size;
printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB );
data = malloc(fileSize);
bytesRead = fread( data, sizeof(unsigned char), fileSize, fp );
free(data);
if( bytesRead != fileSize )
{
printf( "Error reading file. Unexpected number of bytes read: %lu\n", (unsigned long) bytesRead );
End(fp);
exit(EXIT_FAILURE);
}
return 0;
}
int main( int argc, char ** argv )
{
initialize(argc, argv);
readFile(fp);
/* We now have a pointer to the first byte of data in a copy of the file, have fun
unsigned char * data <--- this is the pointer */
End(fp);
return 0;
}
There are no compile errors just functionality
I was attempting to make a simple XOR crypter in c. I found out that the crypting part is not a problem because when the XOR function is used twice on the same string it returns the the exact string I sent back. The problem I believe is therefore not with the crypting part, I believe that the problem occurs when writing the file.
Function the error is within
int xorFile (char *infile, char *outfile) {
FILE *in,
*out;
long lSize;
char *buffer;
in = fopen ( infile , "rb" );
out = fopen(outfile, "wb");
if( !in ) perror(infile),exit(1);
fseek( in , 0L , SEEK_END);
lSize = ftell( in );
rewind( in );
/* allocate memory for entire content */
buffer = (char*)calloc( 1, lSize+1 );
if( !buffer ) fclose(in),fputs("memory alloc fails",stderr),exit(1);
/* copy the file into the buffer */
if( 1!=fread( buffer , lSize, 1 , in) )
fclose(in),free(buffer),fputs("entire read fails",stderr),exit(1);
/* do your work here, buffer is a string contains the whole text */
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
fclose(in);
free(buffer);
fclose(out);
return 0;
}
What I believe causes the error
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
Full Program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define XOR_KEY 0x6F
int xorFile (char *infile, char *outfile) {
FILE *in,
*out;
long lSize;
char *buffer;
in = fopen ( infile , "rb" );
out = fopen(outfile, "wb");
if( !in ) perror("blah.txt"),exit(1);
fseek( in , 0L , SEEK_END);
lSize = ftell( in );
rewind( in );
/* allocate memory for entire content */
buffer = (char*)calloc( 1, lSize+1 );
if( !buffer ) fclose(in),fputs("memory alloc fails",stderr),exit(1);
/* copy the file into the buffer */
if( 1!=fread( buffer , lSize, 1 , in) )
fclose(in),free(buffer),fputs("entire read fails",stderr),exit(1);
/* do your work here, buffer is a string contains the whole text */
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
fclose(in);
free(buffer);
fclose(out);
return 0;
}
int main (int argc, char *argv[]) {
if (argc <= 2) {
fprintf (stderr, "Usage: %s [IN FILE] [OUT FILE]\n" , argv[0]) ;
exit (1);
}
xorFile (argv[1], argv[2]) ;
}
Tested causes
Checked on multiple OS's
Checked on different file formats
Checked on different privileges
Checked on different compilers as well(ran out of things to test)
Additional infomation
When I encrypted a copy of the source file and decrypted it, all that remained was #include <std
The problem you're experiencing is caused by your loop exiting prematurely. The following test will stop as soon as it encounters a null byte:
for(i=0;buffer[i]!='\0';i++)
To encrypt the entire file, this needs to be changed to:
for(i=0;i<lSize;i++)
This will be a problem not only for non-text files, but also for decrypting, since the encryption process will introduce zero bytes for any characters that match your XOR_KEY. For instance, if your XOR_KEY is 0x69, which is an ascii 'i', your encrypted file will contain a zero byte in place of each 'i'. When decrypting it, it will cut the file off at the first such character, which explains what you've been seeing. This will correct that.
buffer[i] ^= XOR_KEY;
fputc(buffer[i] ^ XOR_KEY,out);
First, the program looks at the character in buffer[i], XORs it, and stores the XORed character back in buffer[i].
Then, it looks at the character in buffer[i] (which is now XORed), XORs it again, and writes that to out.
So the character that gets written to out has been XORed twice - so it's just the original character.
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.