I am trying to write code to test the speed of lz4 compression instead of using -b code in terminal.
I am using ubuntu Ubuntu 20.04.2 LTS. And visual studio ide.
Here is my code, it has some trouble when running the second time of the for loop in main.
This line:
fread(src,16384,1,fc);
When i = 1, it works as I expected. However, when i = 2, the malloc() problem just pop up.
//The split file function works perfectly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lz4.h"
int splitFile(char* fileIn, size_t maxSize);
#include "lz4.c"
int main()
{
time_t start,end;
int compress, decompress;
int64_t num_f=0;
int64_t i;
char* src=malloc(16384);
int srcSize= 16385;//(int)(strlen(src) + 1);
int dstCapacity=0;
int compressed_data_size=0;
char* compressed_data = malloc((size_t)dstCapacity);
char buff[200];
FILE * fc;
num_f = splitFile("/home/ziruo/research/1stpro/test.txt",16384);
printf("num_f=%ld\n",num_f);
start = time(NULL);
for( i = 1; i <= num_f; i++)
{
sprintf(buff,"/home/ziruo/research/1stpro/test.txt.%03d",i);
printf("buff %s\n",&buff);
if (compressed_data == NULL)
{
printf("faild to generae storage\n");
}
fc = fopen(buff,"r");
printf("fc is: %d\n",fc);
fread(src,16384,1,fc);
srcSize=(int)(strlen(src) + 1);
dstCapacity= LZ4_compressBound(srcSize)
compressed_data_size = LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
printf("data size ratio %.2f\n", (float)compressed_data_size/srcSize);
}
end = time(NULL);
printf("time used(s): %f\n",difftime(end,start));
return 0;
}
int splitFile(char* fileIn, size_t maxSize)
{
int result = 0;
FILE* fIn;
FILE* fOut;
char buffer[1024 * 16];
size_t size;
size_t read;
size_t written;
if ((fileIn != NULL) && (maxSize > 0))
{
fIn = fopen(fileIn, "rb");
if (fIn != NULL)
{
fOut = NULL;
result = 1; // we have at least one part
while (!feof(fIn))
{
// initialize (next) output file if no output file opened
if (fOut == NULL)
{
sprintf(buffer, "%s.%03d", fileIn, result);
fOut = fopen(buffer, "wb");
if (fOut == NULL)
{
result = -1;
break;
}
size = 0;
}
// calculate size of data to be read from input file in order to not exceed maxSize
read = sizeof(buffer);
if ((size + read) > maxSize)
{
read = maxSize - size;
}
// read data from input file
read = fread(buffer, 1, read, fIn);
if (read == 0)
{
result = -1;
break;
}
// write data to output file
written = fwrite(buffer, 1, read, fOut);
if (written != read)
{
result = -1;
break;
}
// update size counter of current output file
size += written;
if (size >= maxSize) // next split?
{
fclose(fOut);
fOut = NULL;
result++;
}
}
// clean up
if (fOut != NULL)
{
fclose(fOut);
}
fclose(fIn);
}
}
return (result);
}
And here is the picture of error
enter image description here
Related
For my CS class I need to write a program that reads an entire file. I've researched a whole bunch of different ways to do this with a string (the two for loops inside the while loops) and I've combined it with the way I was taught to read through a whole file. The problem is you can't index the frequency list with a char variable type (line). Is there an easier way to read through the file and do this?
# define MAX 200
void replace_most_freq(const char *filename, char c, FILE *destination) {
// your code here
FILE *in_file = NULL;
in_file = fopen(filename, "r");
if (!in_file) {
fprintf(destination,
"Error(replace_most_freq): Could not open file %s\n", filename);
fclose(in_file);
return;
}
int i, max = -1, len;
int freq[256] = { 0 };
char line[MAX], result;
while (fgets(line, sizeof(line), in_file)) {
len = strlen(line);
for (i = 0; i < len; i++) {
freq[line[i]]++;
}
}
while (fgets(line, sizeof(line), in_file)) {
len = strlen(line);
for (i = 0; i < len; i++) {
if (max < freq[line[i]]) {
max = freq[line[i]];
result = line[i];
}
}
}
printf("Most frequent char = %c\n", result);
return;
}
Your initial loop is almost correct: you should convert the char to an unsigned char to avoid undefined behavior on negative char values on platforms where char is signed.
The second loop is incorrect: there is no need to read from the file, just iterate over the freq array to find the largest count.
Here is a modified version:
#include <limits.h>
#include <stdio.h>
void replace_most_freq(const char *filename, char newc, FILE *destination) {
FILE *in_file = fopen(filename, "r");
if (!in_file) {
fprintf(stderr,
"Error(replace_most_freq): Could not open file %s\n", filename);
return;
}
int c, max, maxc;
int freq[UCHAR_MAX] = { 0 };
while ((c = getc(in_file)) != EOF) {
freq[c]++;
}
max = freq[maxc = 0];
for (c = 1; c < UCHAR_MAX; c++) {
if (max < freq[c])
max = freq[maxc = c];
}
printf("Most frequent char = %c (%d)\n", max, max);
rewind(in_file);
while ((c = getc(in_file)) != EOF) {
if (c == maxc)
c = newc;
putc(c, destination);
}
}
You can read file in much larger chunks:
#define BUFFSIZE (4*1024*1024)
int findMax(const size_t *, size_t);
int replace_most_freq(const char *filename, char c, FILE *destination) {
int result = 1;
FILE *fi ;
size_t freq[256] = { 0 };
size_t dataChunkLength;
long fileLength;
unsigned char *databuff = malloc(BUFFSIZE);
if(!databuff)
{
result = -2;
goto function_exit;
}
fi = fopen(filename, "r");
if (!fi)
{
result = -1;
goto function_exit;
}
if (fseek(fi, 0, SEEK_END) == -1)
{
result = -3;
goto function_exit;
}
fileLength = ftell(fi);
if (fileLength == -1)
{
result = -4;
goto function_exit;
}
if (fseek(fi, 0, SEEK_SET) == -1)
{
result = -3;
goto function_exit;
}
while(fileLength)
{
if(fileLength <= BUFFSIZE) dataChunkLength = fileLength;
else dataChunkLength = BUFFSIZE;
size_t bytesRead = fread(databuff, 1, dataChunkLength, fi);
if(bytesRead != dataChunkLength)
{
if(feof(fi) || ferror(fi))
{
result = -4;
goto function_exit;
}
}
for(size_t index = 0; index < bytesRead; index++)
{
freq[databuff[index]]++;
}
fileLength -= bytesRead;
}
int mostFrequent;
printf("The most freq char is 0x%02x\n", mostFrequent = findMax(freq, 256));
function_exit:
free(databuff);
if (fi) fclose(fi);
return result;
}
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
How to get the string size in bytes?
(6 answers)
What are the valid signatures for C's main() function?
(5 answers)
The Definitive C Book Guide and List
(1 answer)
Closed 1 year ago.
I am trying to write code to test the speed of lz4 compress and decompress
However, when I add the decompress function in the code, the error "corrupted size vs. prev_size" starts to show up.
In my mind, I think the problems should be in the calloc function of src. Because the program stops at free(src) when running debug.
Her is my code.
(the lz4.h and lz4.c is on https://github.com/lz4/lz4/tree/355f60952938e5bd4d45118af720d4b8fb0c8a09
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lz4.h"
int splitFile(char* fileIn, size_t maxSize);
#include "lz4.c"
int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);
int LZ4_compressBound(int inputSize);
int main()
{
clock_t start_lz4_c,end_lz4_c,start_lz4_d,end_lz4_d;
double compress_time,large_time,decompress_time,compress_speed,decompress_speed,small_time_c,small_average_time_c,small_time_d,small_average_time_d;
int64_t num_f=0;
int64_t i;
char * temp_src=0;
int srcSize= 0;
int dstCapacity=16384;
int lz4_compressed_data_size=0,lz4_decompressed_data_size=0;
int size_after_comp=0;
int size_before_comp=0;
int size_of_file=0;
char* compressed_data = malloc((size_t)dstCapacity);
char buff[200];
FILE * fc;
FILE * ft;
//split file
num_f = splitFile("/home/ziruo/research/1stpro/test.txt",16384);
printf("num_f=%ld\n",num_f);
//read the length for file
ft = fopen("/home/ziruo/research/1stpro/test.txt","r");
fseek(ft,0,SEEK_END);
size_of_file = ftell(ft);
printf("file len = %d\n",size_of_file);
fclose(ft);
//main loop
for( i = 1; i <= num_f; i++)
{
char* src=calloc(16384,1);
char* regen_buffer = calloc(srcSize,1);
//read in
sprintf(buff,"/home/ziruo/research/1stpro/test.txt.%03ld",I);
if (compressed_data == NULL)
{
printf("faild to generae storage\n");
}
fc = fopen(buff,"r");
fread(src,16384,1,fc);
srcSize=(int)(strlen(src) + 1);
fclose(fc);
small_time_c = 0;
small_time_d = 0;
if(size_of_file <= 100000000)
{
int a;
for(a = 1;a<=10;a++)
{
start_lz4_c = clock();
dstCapacity= LZ4_compressBound(srcSize);
lz4_compressed_data_size = LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
end_lz4_c = clock();
start_lz4_d = clock();
lz4_decompressed_data_size = LZ4_decompress_safe(compressed_data,regen_buffer,lz4_compressed_data_size,srcSize);
end_lz4_d = clock();
small_time_c += ((double)(end_lz4_c-start_lz4_c))/CLOCKS_PER_SEC;
small_average_time_c = small_time_c/10;
small_time_d += ((double)(end_lz4_d-start_lz4_d))/CLOCKS_PER_SEC;
small_average_time_d = small_time_d/10;
}
printf("time %f\n",small_average_time_d);
compress_time += small_average_time_c;
decompress_time += small_average_time_d;
}
else
{
start_lz4_c = clock();
dstCapacity= LZ4_compressBound(srcSize);
LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
end_lz4_c = clock();
large_time = ((double)(end_lz4_c-start_lz4_c))/CLOCKS_PER_SEC;
//printf("time %f\n",large_time);
//compress_time += large_time;
}
//calculate time & speed
size_before_comp += srcSize;
size_after_comp += lz4_compressed_data_size;
printf("decompressed_data_size is %d\n",lz4_decompressed_data_size);
printf("decompression speed: %fMB/s\n",size_after_comp/(decompress_time *1000000));
free(src);
free(regen_buffer);
}
printf("before %d after %d\n",size_before_comp,size_after_comp);
printf("compression speed: %fMB/s\n",size_before_comp/(compress_time*1000000));
printf("compression ratio: %f\n",(float) size_before_comp/size_after_comp);
printf("time used(s): %f\n",compress_time);
printf("decompressed_data_size is %d\n",lz4_decompressed_data_size);
printf("decompression speed: %fMB/s\n",size_after_comp/(decompress_time *1000000));
return 0;
}
int splitFile(char* fileIn, size_t maxSize)
{
int result = 0;
FILE* fIn;
FILE* fOut;
char buffer[1024 * 16];
size_t size;
size_t read;
size_t written;
if ((fileIn != NULL) && (maxSize > 0))
{
fIn = fopen(fileIn, "rb");
if (fIn != NULL)
{
fOut = NULL;
result = 1; // we have at least one part
while (!feof(fIn))
{
// initialize (next) output file if no output file opened
if (fOut == NULL)
{
sprintf(buffer, "%s.%03d", fileIn, result);
fOut = fopen(buffer, "wb");
if (fOut == NULL)
{
result = -1;
break;
}
size = 0;
}
// calculate size of data to be read from input file in order to not exceed maxSize
read = sizeof(buffer);
if ((size + read) > maxSize)
{
read = maxSize - size;
}
// read data from input file
read = fread(buffer, 1, read, fIn);
if (read == 0)
{
result = -1;
break;
}
// write data to output file
written = fwrite(buffer, 1, read, fOut);
if (written != read)
{
result = -1;
break;
}
// update size counter of current output file
size += written;
if (size >= maxSize) // next split?
{
fclose(fOut);
fOut = NULL;
result++;
}
}
// clean up
if (fOut != NULL)
{
fclose(fOut);
}
fclose(fIn);
}
}
return (result);
}
I've been developing a guessing game in which the goal is to guess the character selected by the user among specific characters, anyway, my first and only idea is to create an array with the questions to be asked, and each question has its options like in the code below I'm a newbie in C language so that I there are several things which I'm not sure how to handle. In short, I'd like to know how can I loop over the array showing to the user the questions with its questions to be answered? Here's the code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 500
#define LINE 200
//Read file and append to an array buffer
char *characters(){
char *source = NULL;
FILE *fp = fopen("file.txt", "r");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
}
fclose(fp);
}
return source;
}
char *strndup(const char *s, size_t n) {
char *p;
size_t n1;
for (n1 = 0; n1 < n && s[n1] != '\0'; n1++)
continue;
p = malloc(n + 1);
if (p != NULL) {
memcpy(p, s, n1);
p[n1] = '\0';
}
return p;
}
// User input
char *input(){
char *value;
char buffer[10];
int j = 0;
while( j < 1 && fgets(buffer, 10, stdin) != NULL){
value = strndup(buffer, 10);
j++;
}
return value;
}
// Main function
int main (void)
{
char *questions[] = {
"Genre",{"male","female"},
"Hair", {"black","red","blond"},
"Cloths",{"dress","shirt","pants"},
"pet", {"dog","cat","pig"}
};
int asked[4] = {0};
char *answers[5];
char buffer[6];
srand(time(NULL));
for (int i = 0; i < 4; i++) {
int q = rand() % 4;
while (asked[q])
q = rand() % 4;
asked[q]++;
printf ("%s\n", questions[q]);
answers[i] = input();
}
for(int i = 0; i < 4; i++)
{
printf(" %s ",answers[i]);
}
return 0;
}
That's the file's structure I'll compare as long as I have all the answers from the user.
female,blond,vestido,pig,character b
male,black,shirt,pants,dog,character c
male,black,shirt,pants,cat,character d
female,blond,dress,cat,character A
male,red,shirt,pants,pig,character e
I am writing a program to compare two binary files and plot the first difference. I want to read 16 bytes of data from each file continuously and compare them. For that I am storing 16 bytes from both file into char *buffer1, buffer2. When I print the output I am getting that buffer1 has both the data of file1 and file2.
The code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void printConversion(char *buf1, char *buf2) {
size_t len = strlen(buf1);
char *binary = malloc(len * 8 + 1);
binary[0] = '\0';
for (size_t i = 0; i < len; ++i) {
char ch = buf1[i];
for (int j = 7; j >= 0; --j) {
if (ch & (1 << j)) {
strcat(binary,"1");
} else {
strcat(binary,"0");
}
}
}
printf("File1: %s\t", binary);
free(binary);
printf("File2:");
for (int i = 0; i < sizeof(buf2); i++) {
printf("%x", buf2[i] - '0');
}
}
void fileRead(FILE *fp, char *buf, int count) {
fseek(fp, count, SEEK_SET);
fread(buf, 1, 16, fp);
}
int fileSize(FILE *fp) {
fseek(fp, 0, SEEK_END);
int size = ftell(fp) + 1;
return size;
}
int main(int argc, char *argv[]) {
printf("***Binary File Comparator***\n ");
int count = 0;
int index = 0;
char buffer1[16];
char buffer2[16];
char buffer3[16];
char buffer4[16];
// Invalid Number of Arguments
if (argc < 3 || argc > 3) {
printf("Invalid Number of Arguments\n");
}
FILE *fp1, *fp2;
fp1 = fopen(argv[1], "rb");
int size = fileSize(fp1);
int size1 = size;
fclose(fp1);
while (size > 1) {
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer1, count);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer2, count);
if (size1 < count) {
int lastSize = count - size1;
count = count + lastSize;
fclose(fp2);
} else {
count = count+16;
fclose(fp2);
}
**printf("buffer1:%s\tbuffer2:%s\n", buffer1, buffer2)**;
size = size - 16;
int result = strcmp(buffer1, buffer2);
if (result != 0) {
for (int i = 0; i < sizeof(buffer1); i++) {
if (buffer1[i] != buffer2[i]) {
int count1 = (count - 16) + i;
index++;
if (index == 1) {
printf("Byte_Offset:%x\n", count1);
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer3, count1);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer4, count1);
fclose(fp2);
printConversion(buffer3, buffer4);
break;
}
} else {
continue;
}
}
}
}
}
I have tried to highlight the printf part that is printing my buffer1 and buffer2
The output is as follows:
buffer1:83867715933586928386771593358692 buffer2:8386771593358692
buffer1:49216227905963264921622790596326 buffer2:4921622790596326
buffer1:40267236116867294026723611686729 buffer2:4026723611686729
buffer1:82306223673529228230622367352922 buffer2:8230622367352922
buffer1:25869679356114222586967935611422 buffer2:2586967935611422
Can anybody help what I am doing wrong. Please point me the error and what optimization changes could be done in code. I am at learning stage your feedback will be very helpful.
You are complicating the task by reading 16 bytes at a time. If the goal is to indicate the first difference, just read one byte at a time from both files with getc() this way:
int compare_files(FILE *fp1, FILE *fp2) {
unsigned long pos;
int c1, c2;
for (pos = 0;; pos++) {
c1 = getc(fp1);
c2 = getc(fp2);
if (c1 != c2 || c1 == EOF)
break;
}
if (c1 == c2) {
printf("files are identical and have %lu bytes\n", pos);
return 0; // files are identical
} else
if (c1 == EOF) {
printf("file1 is included in file2, the first %lu bytes are identical\n", pos);
return 1;
} else
if (c2 == EOF) {
printf("file2 is included in file1, the first %lu bytes are identical\n", pos);
return 2;
} else {
printf("file1 and file2 differ at position %lu: 0x%02X <> 0x%02X\n", pos, c1, c2);
return 3;
}
}
In terms of efficiency, reading one byte at a time does not pose a problem if the streams are buffered. For large files, you can get better performance by memory mapping the file contents if available on the target system and for the given input streams.
Not an actual answer, but a word on optimisation. You can increase the speed of the program if you have a bigger buffer. Basically the larger the buffer the faster the program runs HOWEVER the speed you gain from just making it larger will increase logarithmically.
Here is a picture of a graph that will help you understand. Also, what i mentioned applies to any simmilar situation. This includes: Copying files, filling the sound buffer etc. Loading the entire file in your RAM first and operationg on it will usually be faster than loading parts of it. Ofc this is not possible with larger files but still this is what you should aim for if you want speed.
PS: I'm writting here because i don't have rep to comment.
EDIT: I came up with solution but since you did not state what you need to do with your buffer3 and buffer4 i packed it up inside a function.
If you are sure that you are only going to use 16 bytes as a buffer size, remove the nBufferSize parameter and replace the buffer dynamic allocation with a static one.
If after the execution you need the buffers, add them as parameters and keep the nBufferSize param. Keep in mind that if you intend to use them outside the function, you should also allocate them outside the function, so things don't get messy.
/** Returns 0 if files are identical, 1 if they are different and -1 if there
is an error. */
int FileCmp(char* szFile1, char* szFile2, int nBufferSize)
{
FILE *f1, *f2;
f1 = fopen(szFile1, "rb");
f2 = fopen(szFile2, "rb");
// Some error checking?
if (f1 == NULL || f2 == NULL)
return -1;
// You can check here for file sizes before you start comparing them.
// ...
// Start the comparrison.
/// Replace this part with static allocation. --------
char* lpBuffer1 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer1 == NULL) // close the files and return error.
{
fclose(f1);
fclose(f2);
return -1;
}
char* lpBuffer2 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer2 == NULL) // close the files, free buffer1 and return error.
{
free(lpBuffer1);
fclose(f1);
fclose(f2);
return -1;
}
/// --------------------------------------------------
while(1)
{
unsigned int uRead1 = fread(lpBuffer1, sizeof(char), nBufferSize, f1);
unsigned int uRead2 = fread(lpBuffer2, sizeof(char), nBufferSize, f2);
if (uRead1 != uRead2)
goto lFilesAreDifferent;
for(unsigned int i = 0; i < uRead1; i++)
if (lpBuffer1[i] != lpBuffer2[i])
goto lFilesAreDifferent;
if ((feof(f1) != 0) && (feof(f2) != 0))
break; // both files have nothing more to read and are identical.
goto lSkip;
lFilesAreDifferent:
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 1;
lSkip:;
}
// The files are the same. Close them, free the buffers and return 0.
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 0;
}
A simple Demo:
#define BUFFER_SIZE 16
int main(int nArgs, char** szArgs)
{
if (nArgs != 3)
{
printf("Invalid number of arguments.");
return 0;
}
int nResult = FileCmp(szArgs[1], szArgs[2], BUFFER_SIZE);
switch (nResult)
{
case 0: printf("Files [%s] and [%s] are identical.", szArgs[1], szArgs[2]); break;
case 1: printf("Files [%s] and [%s] are different.", szArgs[1], szArgs[2]); break;
case -1: printf("Error."); break;
}
return 0;
}
EDIT II: Personally, i have never used the C standard FILE library (it was either C++ fstream or pure win32 fileapi) so don't take my word here for granted but fread is the fastest function i could find (faster than fgets or fgetc). If you want even faster than this you should get into OS dependant functions (like ReadFile() for Windows).
chqrlie's solution using getc is absolutely the right way to do this. I wanted to address some points brought up in comments, and find it's best to do that with code. In one comment, I recommend pseudo code which could be confusing (namely, you can't write fwrite(file1...) || fwrite(file2 ...) because of the short circuit. But you can implement the idea of that with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Compare two files, 16 bytes at a time. (Purely to demonstrate memcmp.
* Clearly, this should be implemented with getc.)
*/
FILE * xfopen(const char *, const char *);
size_t xfread(void *, FILE *, const char *);
int
main(int argc, char **argv)
{
FILE *fp[2];
size_t n[2];
char buf[2][16];
unsigned count = 0;
if(argc != 3) { return EXIT_FAILURE; }
fp[0] = xfopen(argv[1], "r");
fp[1] = xfopen(argv[2], "r");
do {
n[0] = xfread(buf[0], fp[0], argv[1]);
n[1] = xfread(buf[1], fp[1], argv[2]);
if( n[0] != n[1] || (n[0] && memcmp(buf[0], buf[1], n[0]))) {
fprintf(stderr, "files differ in block %u\n", count);
return 1;
}
count += 1;
} while(n[0]);
puts("files are identical");
return 0;
}
size_t
xfread(void *b, FILE *fp, const char *name)
{
size_t n = fread(b, 1, 16, fp);
if(n == 0 && ferror(fp)) {
fprintf(stderr, "Error reading %s\n", name);
exit(EXIT_FAILURE);
}
return n;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = strcmp(path, "-") ? fopen(path, mode) : stdin;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
I'm trying to change the bytes corresponding to file size in the header of a .wav file, which are the 4th and 40th bytes. Currently, I am copying the entire header to a buffer, attempting to edit it there and then writing it to a destination file, but it doesn't seem to work.
int main(int argc, char * argv []){
int delay = atoi(argv[1]);
FILE * source = fopen(argv[2], "rb");
FILE * destination = fopen(argv[3], "wb");
void * header = malloc(44); // size of a wav file header
fread(header, sizeof(header), 1, source);
// my attempt at changing the 4nd and 40th bytes
sizeptr1 = (unsigned int *)(header + 4);
sizeptr2 = (unsigned int *)(header + 40);
*sizeptr1 = *sizeptr1 + delay;
*sizeptr2 = *sizeptr2 + delay
fwrite(header, sizeof(header), 1, destination);
return 0;
}
What would the most efficient way to change these bytes and write the new header to the output file be?
A byte array is easiest, if you are sure which bytes you want to change. For example the 4th byte is at buffer[3].
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 1024
#define HEADSIZE 44
int main(int argc, char * argv []) {
int delay;
size_t bytes;
FILE * source = NULL;
FILE * destination = NULL;
unsigned char buffer[BUFFSIZE];
if (argc < 4) return 0; // check enough args
delay = atoi(argv[1]);
if (NULL == (source = fopen(argv[2], "rb")))
return 0;
if (NULL == (destination = fopen(argv[3], "wb")))
return 0;
// copy & alter buffer
if (HEADSIZE != fread(buffer, 1, HEADSIZE, source))
return 0;
buffer[4] = delay;
buffer[40] = delay;
if (HEADSIZE != fwrite(buffer, 1, HEADSIZE, destination))
return 0;
// copy rest of file
while ((bytes = fread(buffer, 1, BUFFSIZE, source)) != 0) {
if (bytes != fwrite(buffer, 1, bytes, destination))
return 0;
}
if (0 == fclose(destination))
printf("Success\n");
fclose (source);
return 0;
}
This is one way of editing bytes in a file, check if it will works for you.
int
ChangeHeaderByte(
const char* fileName,
unsigned int pos[],
unsigned int val[],
unsigned int size
)
{
unsigned int i = 0;
unsigned int temp = 0;
FILE * fileHandle = fopen(fileName, "r+");
if (fileHandle == 0) {
fprintf(stderr,"Error: %s : %d : Failed to open file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
for ( i = 0; i < size ; ++i )
{
if ( fseek(fileHandle, pos[i] - (unsigned int)1, SEEK_SET) == 0 )
{
if ( fread(&temp,sizeof(unsigned int),1,fileHandle) == 1 )
{
if ( fseek(fileHandle, pos[i] - (unsigned int)1 , SEEK_SET) == 0 )
{
val[i] += temp;
fwrite(&val[i], sizeof(unsigned int), 1, fileHandle);
}
else
{
fprintf(stderr,"Error: %s : %d : fseek() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
}
else
{
fprintf(stderr,"Error: %s : %d : fread() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
} else {
fprintf(stderr,"Error: %s : %d : fseek() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
}
fclose(fileHandle);
return (0);
}
int main(void)
{
const unsigned int size = 2;
char fileName[] = "C:\\Users\\sridhar\\test\\test.wav";
unsigned int pos[2] = { 4 , 40 };
unsigned int val[2] = { 123456, 123456 };
ChangeHeaderByte(fileName,pos,val,size);
return 0;
}