Broken files in C - c

I made a simple script to rewrite one file contents into another.
Here's code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char filename[1024];
scanf("%s", &filename);
// printf("Filename: '%s'\n", filename);
int bytesToModify; scanf("%d", &bytesToModify);
FILE *fp;
fp = fopen(filename, "r");
fseek(fp, 0, SEEK_END);
int fSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("%d\n", fSize);
char *buf = malloc(fSize*sizeof(char));
for (int i = 0; i < fSize; i++) {
buf[i] = getc(fp);
}
fclose(fp);
FILE *fo;
fo = fopen("out_file.txt", "w");
for (int i = 0; i < fSize; i++) {
fwrite(&buf[i], 1, 1, fo);
}
fclose(fo);
return 0;
}
Even on small file like this I can see the artifact. Cyrillic sybmol 'я' is coming in the end of file.
If I'll try to rewrite executable file, i get this:
99% of file just turned to these symbols. What is wrong with my code?
I'm using CodeBlocks with GCC Compiler, version 10.1.0.
My Operation System is Windows 10.
Thanks for your help.

You did not open the file in binary mode: "rb" and "wb". Therefore, fgetc will turn all \r\n to a single \n.
For each line terminator there is one character less read. Yet you attempt to read nevertheless, and fgetc will return EOF (and fgetc returns an int, not char). As EOF has value -1 on Windows, when written to file converted to unsigned char this results in Я in the encoding you're using in Notepad (most likely Windows-1251).
Furthermore, since you're using fwrite, then you could similarly use fread. And no need to read, write the characters one at a time, just use
char *buf = malloc(fSize);
int bytesRead = fread(buf, 1, fSize, fp);
fclose(fp);
and
int bytesWritten = fwrite(buf, 1, bytesRead, fo);

Related

Getting excess characters with fread() in C

Okay, so I have tried to read a whole file with fread(), and I can do it successfully, but the longer the file, the more the excess characters I get on the output.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
FILE* fpointer = fopen("test.txt", "r");
char* wholeFile;
long int fileSize;
if (fpointer == NULL) return 0;
fseek(fpointer, 0, SEEK_END);
fileSize = ftell(fpointer);
rewind(fpointer);
printf("fileSize == %ld\n", fileSize);
wholeFile = (char*)malloc(fileSize+1, sizeof(char));
if (wholeFile == NULL) return 1;
fread(wholeFile, sizeof(char), fileSize, fpointer);
fclose(fpointer);
wholeFile[fileSize] = '\0';
printf("This is whole file:\n\n%s", wholeFile);
free(wholeFile);
return 0;
}
If the file looks like this:
This is cool file.
I get this as output:
This is cool file.²²²²
And if the file is like this:
This
is
cool
file.
I get this as the output:
This
is
cool
file.═══²²²²
Any idea where I'm wrong?
EDIT: Edited code according to comments.
You need to allocate one more than the size of the file and set the last position in the buffer to 0.
C expects character arrays to be null terminated.
Use "rb" to open the file in binary mode. This will ensure you get a reliable count of bytes in the file from Windows.
FILE* fpointer = fopen("test.txt", "rb");
wholeFile = (char*)malloc(fileSize + 1);
wholeFile[fileSize] = '\0';

XOR failing to decrypt certain files

The following code manages to encrypt any file I try, but it only manages to decrypt .txt files. When I try decrypting .mp3, .png, .mp4 files which I have encrypted, it fails to do so.
So I am wondering why this is the case? If it successfully manages to decrypt .txt files, why does it fail to do so with the other file formats I've tried (mentioned before)? Because if I understand XOR encryption correct it returns the original string running it a second time, thus I should be able to reopen the file and it should work normally since the data should be decrypted, r-right?
Feel free to bash me if I am being stupid here.
#include <filesystem>
#include <cstdio>
#include <Windows.h>
int main() {
const std::filesystem::path& path = "folder\\";
FILE* pFile, *pFile1;
char key = '¤';
//get files in dir
for (const std::filesystem::directory_entry &p : std::filesystem::directory_iterator(path)) {
std::filesystem::path filename = p.path().filename();
std::string tmp = path.string() + filename.string();
fopen_s(&pFile, tmp.c_str(), "rb");
if (pFile) {
//for size purposes
char* buffer = 0;
long size;
fseek(pFile, 0L, SEEK_END);
size = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
//rewind(pFile);
buffer = new char[size+1];
//set to zero to remove random chars
memset(buffer, 0, size+1);
//get filecontent
fgets(buffer, size+1, pFile);
fclose(pFile);
//XOR-crypt text/data
for (int i = 0; i < size+1; i++) {
buffer[i] ^= key;
}
//open for writing
fopen_s(&pFile1, tmp.c_str(), "wb");
//write back to file
fputs(buffer, pFile);
fclose(pFile1);
delete[] buffer;
}
}
}

Reading hex value from image in C

I'm trying to read the hex values from an image file using C. In Linux, this code works fine, but with Windows it reads only the first 334 bytes and I don't understand why.
The code to read the file is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
void readHexFile(char* path) {
FILE *fp;
if ((fp = fopen (path, "r")) != NULL) {
struct stat st;
stat(path, &st);
int i;
int ch;
for (i = 0; i < st.st_size; i++) {
ch = fgetc(fp);
printf("%x ", ch);
}
fclose(fp);
}
else {
return NULL;
}
}
st.st_size comes from <sys/stat.h> package and contains the right value (the size, in bytes, of the image file)
This image show what my program outputs, and the actual binary content of the file it is reading:
As you see after the sequence of 17, 18, 19 there is also hex values but my program prints ffffffff repeatedly.
You opened the file in a text mode, and not as binary. Different platforms may behave differently.
In this case, Microsoft Windows decided that this plain text file ends at the first occurrence of Ctrl+Z (0x1A), and returns EOF for all fgetc afterwards.
Explicitly state that you want to open the file as binary:
fp = fopen ("yourfile", "rb");
and the problem goes away.
I think your loop should look like this:
int ch;
while (!feof(fp)) {
ch = fgetc(fp);
printf("%x ", ch);
}
It's completely unclear to me why you are using st.st_size here.
On Windows, the character 0x1A (Ctrl+Z) is the EOF character for text mode; see this question.
If you're reading from a binary file like a JPEG, you should do so with first opening the file as binary (fopen mode "rb"), then fread into a pre-allocated buffer, the size of which you would determine with ftell with the file pointer at the end of the file:
size_t i, len;
char *buffer = NULL;
fp = fopen(argv[1], "rb");
if(!fp)
// handle error
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len + 1);
if(!buffer)
// handle error
fread(buffer, 1, len, fp);
for(i = 0; i < len; i++)
{
printf("%.2X ", buffer[i]);
}
free(buffer);
buffer = NULL;

Converting Binary File to Text File in C

I'm having an issue trying to convert a Binary File into a text file. Right now, I'm getting an output of "hello 16". I should be getting 5 lines of output, in which the first line should be "hello 32". I'm unsure where I went wrong, but I've been trying to figure it out for a few hours now.
Link to Binary File
void BinaryToText(char *inputFile, char *outputFile) {
unsigned char str[256];
unsigned int num;
int fileLen;
FILE *finp;
FILE *fout;
finp = fopen(inputFile, "r");
fout = fopen(outputFile, "w");
fseek(finp, 0, SEEK_END);
fileLen = ftell(finp);
fseek(finp, 0, SEEK_SET);
while (fread(&fileLen, sizeof(char), 1, finp) == 1) {
fread(&str, sizeof(str), 1, finp);
fread(&num, sizeof(int), 1, finp);
fprintf(fout, "%s %d\n", str, num);
}
fclose(finp);
fclose(fout);
}
You binary file format seems awkward:
you open the input file with "r": it should be opened in binary mode with "rb".
you first attempt to determine the file size with ftell(). Be aware that this will not work for pipes and devices. In you case it would not matter as you do not use fileLen anyway.
in the loop:
you read a single byte that you store in a part of fileLen.
you then read a string of 256 bytes.
you read a number directly, assuming the byte order and size of int is what you expect.
you then print the string, assuming there was a '\0' in the file, otherwise you would invoke undefined behavior.
It is hard to tell what is wrong without seeing the writing code.
Note that the binary file should be open with "rb" to prevent spurious conversion of linefeed sequences on some platforms, notably Windows.
EDIT:
Form the extra information provided in the comments, here is a modified version that should parse you binary file more appropriately:
void BinaryToText(char *inputFile, char *outputFile) {
unsigned char str[256];
unsigned int num; // assuming 32 bit ints
int i, len;
FILE *finp = fopen(inputFile, "rb");
FILE *fout = fopen(outputFile, "w");
while ((len = fgetc(finp)) != EOF) {
fread(str, len, 1, finp);
str[len] = '\0';
num = (unsigned int)fgetc(finp) << 24;
num |= fgetc(finp) << 16;
num |= fgetc(finp) << 8;
num |= fgetc(finp);
fprintf(fout, "%s %d\n", (char*)str, num);
}
fclose(finp);
fclose(fout);
}

Reverse file text

I'm trying to make a program that uses fgets to take the text from a preexisting file, invert it and then write it to another file. This is the code I've written so far:
#include <stdio.h>
#include <string.h>
int main()
{
int c, d;
FILE *file1, *file2;
char string [100], *begin, *end, temp;
file1 = fopen("StartingFile.txt", "rt");
if (file1 == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fgets(string, 100, file1);
fclose (file1);
begin = string;
end = begin + strlen(string) - 1;
while (end > begin)
{
temp = *begin;
*begin = *end;
*end = temp;
++begin;
--end;
}
file2 = fopen("FinalFile.txt", "wt");
fprintf (file2, "%s", string);
fclose (file2);
printf ("%s\n", string);
return 0;
}
It works fine if the text in the preexisting file is all in one line, but if it has more than one line, only the first one is inverted and written to the new file. I think that fgets can only read one line, so I think I'll have to use a loop, but I'm having trouble implementing it. Can someone give me a hand? Thanks in advance!
To read each line separately from file use fgets in while loop as below,
while(fgets(string, sizeof(string), file1) != NULL)
{
...
}
fclose(file1);
Inside the loop operate on each line to reverse it.
Your code has quite a few logical errors in it. I would recommend using other f* methods instead.
If you want an easy solution, open the file, determine its length, create two buffers of the size of the file, fill the first buffer with the file's contents and then do a loop to copy the reverse to the other buffer, then write that buffer back. Roughly that would look like this:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *file;
file = fopen("StartingFile.txt", "rt");
if (file == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fseek(file, 0, SEEK_END); // move file pointer to end of file
long size = ftell(file); // file pointer position == character count in file
fseek(file, 0, SEEK_SET); // move back to beginning of file
char* buffer = malloc(size * sizeof(char));
fread(buffer, sizeof(char), size, file) // read file contents to buffer
for(long i = 0; i < size/2; ++i)
{
buffer[i] = buffer[size-i-1];
}
fseek(file, 0, SEEK_SET); // The fread set the file pointer to the end so we need to put it to the front again.
fwrite(buffer, sizeof(char), size, file); // Write reverted content
delete buffer;
fclose (file);
}
I haven't tested it and it may contain a few errors since I haven't programmed in C for some time. The only reason to still be programming in C anyways is efficiency and if you want your program to be efficient, the two buffer solution isn't the best either. At least not in terms of memory usage.
I highly recommend getting familiar with all the functions available in C (stdio and so on) cplusplus.com is a great reference for that.
Regards, Xaser

Resources