fread fwrite fseek in C - c

Hello what i am trying to do is to reverse a binary file. The type of the file is wav so for example if the channel number is 2 and bits per sample are 16 each time i will copy 32/8 = 4 bytes. The first think to do is copy the header as it is(that part is ok) and then reverse he data. I've created a code to copy the header and then part of the data from the end this 10 times(for testing) but instead of copying 40 bytes it stops at 20 for some reason(even if it would do it 20 times it would still copy just the 20 bytes). This is the code which does that. I can't spot the mistake if you can see it tell me :) Maybe the mistake is somewhere else so i wrote the full function
void reverse(char **array)
{
int i=0;
word numberChannels;
word bitsPerSample;
FILE *pFile;
FILE *pOutFile;
byte head[44];
byte *rev;
int count;
if(checkFileName(array[2]) == 0 || checkFileName(array[3]) == 0)
{
printf("wrong file name\n");
exit(1);
}
pFile = fopen (array[2] ,"r");
fseek(pFile, 22, SEEK_SET);//position of channel
fread(&numberChannels, sizeof(word), 1, pFile);
fseek(pFile, 34, SEEK_SET);//position of bitsPerSample
fread(&bitsPerSample, sizeof(word), 1, pFile);
count = numberChannels * bitsPerSample;
rewind(pFile);
fread(head, sizeof(head), 1, pFile);
pOutFile = fopen (array[3] ,"w");
fwrite(head, sizeof(head), 1, pOutFile);
count = count/8;//in my example count = 32 so count =4
rev = (byte*)malloc(sizeof(byte) * count);//byte = unsigned char
fseek(pFile, -count, SEEK_END);
for(i=0; i<10 ; i++)
{
fread(rev, count, 1, pFile);
fwrite(rev, count, 1, pOutFile);
fseek(pFile, -count, SEEK_CUR);
}
fclose(pFile);
fclose(pOutFile);
}

sizeof(rev) will evaluate to the size of a pointer. You probably just want to use count instead.
Also, does the line count = count + count do what you want it to? (i.e. it doubles count every iteration)

I would change your fseek to move relatively from the current position (and use count instead of sizeof(rev)):
for(i=0; i<10; i++)
{
fread(rev, count, 1, pFile);
fwrite(rev, count, 1, pOutFile);
fseek(pFile, -count, SEEK_CUR);
}

You need to initialize count to 4 and add 4 to it progressively. Also, sizeof(rev) is only the size of a pointer (4/8 bytes). You need to use sizeof(byte) * count instead. You can also use count in the for directly:
pFile = fopen(array[2] ,"r");
pOutFile = fopen(array[3] ,"w");
rev = (byte*)malloc(sizeof(byte) * count); //byte = unsigned char
for(count = 4; count < 44; count += 4)
{
fseek(pFile, -count, SEEK_END);
fread(rev, sizeof(byte), count, pFile);
fwrite(rev, sizeof(byte), count, pOutFile);
}
fclose(pFile);
fclose(pOutFile);

Related

Understanding fseek() in C

I was learing File I/O in C and was interested in using it to read and write structures to files via fwrite() and fread() functions, now after my code ran successfully I was wondering if I could read a specific structure from an array of structures and put it in some given structure.
Here is my attempt at it
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
fp = fopen("file.txt", "rb+");
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when\
it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 26 and not 51
return 0;
}
Now when I ran the programm I expected 51 a 0 0.00000 as output,
but to my surprise it is picking up the 26th structure and putting it in a[3]
Any help will be appritiated!!
Try changing fopen to use w+ instead of rb+
Also, remove the fseek when creating the file, as mentioned, fwrite definitely advances the file offset after writing data (provided fwrite does write data at all).
Here is the output observed using the modified code below.
gcc main.c
./a.out
51 a 0 0.000000
// main.c
#include <stdio.h>
#include <stdlib.h>
typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;
void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}
int main() {
FILE * fp;
// recommend for this example using w+
// w because it creates the file if the file doesn't exist
// r fails if the file doesn't exist (and that doesn't seem useful here)
// + because you are reading and writing
// avoiding b and choosing POSIX - linux
// may be wrong, if libc docs says b is needed then use b
// my doc "man fopen" says b is ignored
fp = fopen("file.txt", "w+");
// check return values, file pointer exist? fail if not
if (fp==NULL) { printf( "oops file not opened\n" ); return 1; }
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i < 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = 'a';
a[i].toolname[1] = '\0';
a[i].quantity = 0;
a[i].recordno = i + 1;
}
// alternative way to save 100 objects
// if ( fwrite(a, sizeof(tools), 100, fp) != 100 )
// {
// printf( "oops 100 objects not written to file\n" );
// return 1;
// }
for (int i = 0; i < 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
// remove fseek, not needed, fwrite does what is needed here
//fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when
// it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
// no review after this line, it seems to do what author intends
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]
recordprinter(a[3]);
// this gives output 51 as desired
return 0;
}

Why does iterating through this char array increment byte in array instead of array value?

I'm new to c, and having a hard time with memory management.
I have a program that takes an array of files, goes through each file, and copies the array into a value in a struct.
When given a list of files file1.txt, file2.txt, file3.txt
The first iteration through my for loop works as expected. The value taken is as expected file1.txt. On the second loop, the value taken into my GetFileContent() method is ile1.txt (it cut off just the first bit of the first item in the array). If I change the i value to 2, it cuts off the first 2 letters to le1.txt.
char *GetFileContent(char *filePath)
{
char *buffer = NULL;
size_t size = 0;
FILE *file = fopen(filePath, "r");
fseek(file, 0, SEEK_END);
size = ftell(file);
rewind(file);
buffer = malloc((size + 1) * sizeof(*buffer));
fread(buffer, size, 1, file);
fclose(file);
buffer[size] = '\0';
return buffer;
}
int main (void)
{
char *file = {"file1.txt", "file2.txt", "file3.txt"};
int numberOfFiles = sizeof(file);
struct ArrayStoredInHeap myStruct[numberOfFiles];
for(int i = 0; i < numberOfFiles; i++)
{
struct ArrayStoredInHeap tmpStruct;
tmpStruct.entireFile = GetFileContent(&file[i]);
myStruct[i] = tmpStruct;
}
for(int i = 0; i < numberOfFiles; i++)
{
printf("%s \n", myStruct[i].entireFile);
getchar();
}
}
I expected the value in the second time through the loop to be file2.txt as in, the second value in the array, instead of removing 1 character from the array. I'm assuming the memory I'm referencing is moving by one byte, but I'm not sure how that would be happening in this.

SHA - Output of program is different from sha512sum command

In summary, I program for first time with openssl/sha.h and everything goes right in compilation. here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <openssl/sha.h>
int main()
{
int j;
FILE *hash_file = fopen("hash.txt", "wb");
for(j = 0; j < 256; j++)
{
unsigned char md[SHA512_DIGEST_LENGTH];
char* fileName = malloc(sizeof(int));
sprintf(fileName, "%X%s", j, ".txt");
int i;
FILE *file = fopen(fileName, "rb");
SHA512_CTX mdcontext;
int bytes;
unsigned char data[2048];
if(file == NULL)
{
printf("%s can not be opened\n", fileName);
return;
}
SHA512_Init(&mdcontext);
while((bytes = fread(data, 1, 2048, file) != 0))
SHA512_Update(&mdcontext, data, bytes);
SHA512_Final(md, &mdcontext);
for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
{
printf("%x", md[i]);
fprintf(hash_file, "%x", md[i]);
}
// fprintf(hash_file, "\n");
printf("\n");
free(fileName);
fclose(file);
}
fclose(hash_file);
return 0;
}
and I have this output :
711c22448e721e5491d8245b49425aa861f1fc4a15287f735e23799b65cffec5b5abdfddd91cd643aeb3b530d48f5e258e7e230a94ed525c1387bb4e1b
But when I hash same file with sha512sum command in Linux i got this output:
6e3ea4bec3cd738f06f011c2f4ee4f6cd6d12205cafe41c083d52f94d9de4ab8b9e702664a367b633be14024a96e88a140a2e7fee4dc2c6e2f0bd436e281e35b make.sh
what is the problem?
Oh boi!
A tiny little parantheses can make you pull your hair out.
The problem is in this statement while((bytes = fread(data, 1, 2048, file) != 0)). You see, in this statement the != condition will be evaluated first. So, when fread reads (and returns), let's say n number of characters, it checks if n!=0. If it evaluates to true then it sets bytes to 1 (true is casted to 1).
And now, the function SHA512_Update(&mdcontext, data, bytes); becomes SHA512_Update(&mdcontext, data, 1); while it should have been SHA512_Update(&mdcontext, data, n); (where n is the number of characters successfully read).
Solution
Change while((bytes = fread(data, 1, 2048, file) != 0)) to while((bytes = fread(data, 1, 2048, file)) != 0).
Update [Saving the hash in a char array]:
The output of SHA512 is of 128 characters. So, we need a char array of size twice that of SHA512_DIGEST_LENGTH (64). Then, we can just store it in the char array using sprintf.
char hash[SHA512_DIGEST_LENGTH*2];
for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
sprintf(&hash[i*2], "%02x", md[i]);
Why i*2? Because output has a width of 2 bytes. So, result will be stored at hash[i] and hash[i+1].
Now, to print it:
for(i = 0; i < SHA512_DIGEST_LENGTH*2; i++)
printf("%c", hash[i]);
PS:
Read about precedence.
And don't forget to follow the advices in comments to your post, especially the one about using %02x by Steve.

fseek From one line to Another

I want to read into a buffer a couple of lines from a file.txt.
At the moment I fseek and fread every line in a loop. I know what the lines are because I keep a list of their indices. So if I want to read from line 5 to line 10, I know exactly what those lines are in the file.txt. I never have to read the whole file.
I want to do something like this:
char buffer[2000];
FP *fp;
fseek(fp, start_index, end_index, SEEK_SET);
fgets(buffer, 2000, fp);
How do I do something like that? fseek doesn't take that many parameters.
Textfile looks like this
apple: a fruit.
apple pie: a pie made from apples.
If I understood you right, all you'll have to do is calculating the length of your section and read that rather than up to 2000 characters:
fseek(fp, start_index, SEEK_SET);
fread(buffer, sizeof(char), end_index - start_index, fp);
Of course, keep in mind that I didn't include any length/error checking and no null terminator for the buffer etc. You could allocate the buffer dynamically to fix that:
long len = end_index - start_index;
char *buffer = new buffer[len + 1];
fseek(fp, start_index, SEEK_SET);
fread(buffer, sizeof(char), len, fp);
buffer[len] = 0;
you can do it like this.
char buffer[5][1024];//save 5 lines.If a line to a maximum of 1024 characters
char buff_line[1024];//for fgets buff
FILE *fp = NULL;
int start_line = 0;
int end_line = 4;
int cur_line = 0;
int i;
fp = fopen("file.txt","r");
while(fgets(buff_line,1024,fp))
{
if (cur_line >= start_line && cur_line <= end_line)
{
memcpy(buffer[cur_line - start_line],buff_line,sizeof(buff_line));
}
cur_line++;
}
for (i=0;i<=(end_line - start_line);i++)
{
fputs(buffer[i],stdout);
}

Reading a .bmp image with fread()

I am trying to read a .bmp image and write the data into a text file. Code is running fine but the problem is, it cannot read whole image once so I have to call fread() function many times. While doing this my code is repeatedly storing the first read data into the text file. What changes do I have to do in order to read the whole image properly? Below is my code snippet.
int size = width * height;
unsigned char* data = new unsigned char[size];
filename = "image.bmp";
fname = "image_data.txt";
FILE* f = fopen(filename, "rb");
FILE *fp = fopen(fname, "w");
while(totalBytes < size)
{
readsize = fread(data, sizeof(unsigned char), size, f);
totalBytes += readsize;
for(i = 0; i < readsize; i++)
{
fprintf(fp, "%d", data[i]);
if((i % width) == 0 && i != 0)
fprintf(fp, "\n");
}
fseek(f, readsize, SEEK_SET);
readsize = 0;
}
Your fseek call is wrong. After the fread call the file position will be behind the read data, so you can just read on without seeking.
What happened before was that you read X bytes, did an unnecessary but harmless fseek to file position X, then read Y bytes, but did a harmful fseek back to file position X, so you kept reading the same data again.
while(totalBytes < size)
{
readsize=fread(data, sizeof(unsigned char), size, f);
totalBytes+=readsize;
for(i = 0; i < readsize; i++)
{
fprintf(fp,"%d",data[i]);
if((i % width)== 0 && i!=0)
fprintf(fp,"\n");
}
}

Resources