How to read past EOF from getc? - c++

I am writing a XOR encryption program which works fine during encryption but during decryption
the
char ca2=fgetc(f);
gets stuck at one point and no decryption takes place after that my best guess about the problem is (the encrypted file contains all sorts of characters ) as soon as fgetc reaches EOF mark which can be present before the actual end of the file it gets stuck there and stop reading the next characters .
is this some kind of limitation of getc() ? here is my rubbish code
int get_file_size(char filename[])
{
FILE *p_file = NULL;
p_file = fopen(filename,"rb");
fseek(p_file,0,SEEK_END);
int size = ftell(p_file);
fclose(p_file);
return size;
}
int endec(char filename[],char psdw[])
{
FILE *f;
int hashed=0,ed=0;
int inphash=inhash(psdw);
inphash=inphash%50;
f=fopen(filename,"r");
if(f==NULL)
printf("failed");
char temps[999999];
long int crs=0,j=0;
int filesz=get_file_size(filename);
printf("file size = %d\n\n",filesz);
while(1){
inphash=inphash+2;
char ca=(char)inphash;
char ca2=fgetc(f);
printf("%c\n",ca2);
if(crs>=filesz)
break;
temps[crs]= ca2 ^ ca;
crs++;
}
fclose(f);
printf("%d",strlen(temps));
FILE *fp;
fp=fopen(filename,"wt");
for(j=0;j<crs;j++){
putc (temps[j] , fp);
printf("%c",temps[j]);
}
fclose(fp);
}

Your problem is right here:
f=fopen(filename,"r");
You open the file for text reading, not for binary. Your file size function gets it right, but your decoder function does not.
The idiomatic way to read a file character by character using the C-style IO routines is like this:
f = fopen(filename, "rb");
if (!f)
// handle error
int c; // NOTE: int, not char!
while ( (c = fgetc(f)) != EOF )
{
// do something with 'c'
}
This idiom does not require you to get the file size as a separate operation. You can rewrite your XOR "encryption" routine with a simple loop of the above form. It will be much clearer and more concise.
Your entire decoder function could be rewritten as follows: (minus the debug code)
int endec(char filename[], char psdw[])
{
int inphash = inhash(psdw) % 50;
char temp[999999]; // really, should be std::vector<char>
FILE *f;
if ( (f = fopen(filename, "rb")) == NULL )
{
printf("opening for read failed\n");
return -1;
}
size_t crs = 0;
int c;
while ( (c = fgetc(f)) != EOF )
{
inphash += 2;
temp[crs++] = (char)(inphash ^ c);
}
fclose(f);
if ( (f = fopen(filename, "wt")) == NULL )
{
printf("opening for write failed\n");
return -1;
}
if (fwrite(temp, crs, 1, f) != crs)
{
printf("short write\n");
fclose(f);
return -1;
}
fclose(f);
return 0;
}
Not stellar error handling, but it is error handling.

Related

How to get the last line of a binary file in C?

I want to get the last record in a binary file, extract its ID and add one to it to mimic an auto-incrementing ID feature. So for example, if the previous user had an ID of 1, then the next user should have an ID of 2, and so on. The issue is I can't get the last record of the binary file using the code below. How can I go about doing this? Here's my code so far:
#include <stdio.h>
struct Applicant
{
int id;
};
void increment()
{
char fileName = "data.dat";
FILE *file;
// Instantiate the applicant struct
struct Applicant applicant;
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Open the file in 'append binary' mode
file = fopen(fileName, "ab");
// If file does not exist, print error message and exit
if (!file)
{
printf("\nSorry, that file does not exist");
exit(1);
}
// Read the last applicant to get their id
while(1)
{
fread(&previousApplicant, sizeof(previousApplicant), 1, file);
if (feof(file)) { break; }
}
// If there's no previous applicant, set the ID to 100
if (previousApplicant.id == 0)
{
applicant.id = 100;
}
// Otherwise just increment the previous applicant's id and assign it to the new applicant
else
{
applicant.id = previousApplicant.id + 1;
}
fwrite(&applicant, sizeof(applicant), 1, file);
fclose(file);
}
To achieve this, I'm using structs
The way I'd suggest doing it is to call fseek() to seek directly to the last record in the file, read it in to RAM, update it, and write it out again. That way you don't have to read in every record in the file just to update the last one, which would be really inefficient if the file is large and/or you have to perform this operation often.
Something like this:
#include <stdio.h>
#include <stdlib.h>
struct Applicant
{
int id;
};
void increment()
{
const char fileName[] = "data.dat";
// Open the file in 'append binary' mode
FILE *file = fopen(fileName, "a+b");
if (file == NULL)
{
printf("Couldn't open file [%s]\n", fileName);
return;
}
// Seek to the end of the file
if (fseek(file, 0, SEEK_END) != 0)
{
printf("Couldn't seek to the end of the file!\n");
fclose(file);
return;
}
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Check to make sure the file is big enough to hold at least one record
const long fileLengthBytes = ftell(file);
if (fileLengthBytes < sizeof(previousApplicant))
{
printf("File is to short to contain a full record!?\n");
fclose(file);
return;
}
// Check to make sure the file length is an even multiple of the record-length
if ((fileLengthBytes % sizeof(previousApplicant)) != 0)
{
printf("File length (%li) is not a multiple of record size (%zu)!?\n", fileLengthBytes, sizeof(previousApplicant));
fclose(file);
return;
}
// Seek backwards to the start of the last record in the file
if (fseek(file, -sizeof(previousApplicant), SEEK_CUR) != 0)
{
printf("Couldn't seek to the start of the last record in the file!\n");
fclose(file);
return;
}
// Read in the last record in the file
if (fread(&previousApplicant, sizeof(previousApplicant), 1, file) != 1)
{
printf("Couldn't read the last record in the file!\n");
fclose(file);
return;
}
// Increment the record
printf("Incrementing ID of last record in the file from %i to %i\n", previousApplicant.id, previousApplicant.id+1);
previousApplicant.id++;
// Finally, write out the new record in the file with incremented ID
if (fwrite(&previousApplicant, sizeof(previousApplicant), 1, file) != 1)
{
printf("Couldn't write the last record in the file!\n");
fclose(file);
return;
}
// success!
fclose(file);
}
int main(int, char **)
{
increment();
return 0;
}
There were a few problems with your code. You were reading the applicant ID into the applicant struct variable rather than the previousApplicant variable and when reading and writing files it is best to separate out the tasks: first open the file for reading, then when you're ready to write, close it and open it for writing.
Here's the modified working code which will do what you want:
#include <stdio.h>
#include <stdlib.h>
struct Applicant
{
int id;
};
void increment()
{
char* fileName = "data.dat";
FILE *file;
// Instantiate the applicant struct
struct Applicant applicant;
// Will contain details of the last applicant in the file
struct Applicant previousApplicant;
// Open the file in 'append binary' mode
file = fopen(fileName, "rb");
// If file does not exist, print error message and exit
if (!file)
{
printf("\nSorry, that file does not exist");
exit(1);
}
// Read the last applicant to get their id
while(1)
{
fread(&previousApplicant, sizeof(applicant), 1, file);
if( feof(file) ) break;
}
// If there's no previous applicant, set the ID to 100
if (previousApplicant.id == 0)
{
applicant.id = 100;
}
// Otherwise just increment the previous applicant's id and assign it to the new applicant
else
{
applicant.id = previousApplicant.id + 1;
}
fclose(file);
FILE* out = fopen(fileName, "ab");
fwrite(&applicant, sizeof(applicant), 1, out);
printf("%d\n", applicant.id);
fclose(out);
}
void main() {
increment();
}
I am not sure I got the logic of what you are trying to do. As pointed above, you can use just fseek() to move the current pointer for the file.
from the [documentation][1]
int fseek(
FILE *stream,
long offset,
int origin
);
int _fseeki64(
FILE *stream,
__int64 offset,
int origin
);
As for the offset: you can use this pre-defined constants: SEEK_CUR meaning the current position in file, SEEK_SET meaning the beginning and SEEK_END pointing, well, to the END of the file. The current offset from the beginning of file you can get by calling fseek()'s sister, ftell(), that returns a long with the position. First byte is 0. You can for sure seek for any position.
An example:
At first consider this code:
int create(const char* f_name, unsigned int n_rec)
{
Applicant one = {100};
FILE* f = fopen(f_name, "wb");
if (f == NULL) return -1;
for (unsigned i = 0; i < n_rec; i += 1, one.id+= 1)
if (fwrite(&one, sizeof(one), 1, f) != 1)
return 1 + i;
fclose(f);
return n_rec;
}; // create()
This function creates the file and writes down the supplied number of IDs. e.g.
create( "x.dat", 300 )
will go as expected and create x.dat and write 300 IDs starting at 100 --- inclusive --- in the file.
Then the following function in the example below reopens the file, get the last ID used and returns it, and you can use it as a prototype:
int get_last_id(const char* f_name)
{
Applicant one = {0};
int res = 0;
FILE* f = fopen(f_name, "rb+");
if (f == NULL) return -1;
res = fseek(f, SEEK_END, SEEK_SET);
if (res != 0) return -2;
res = fseek(f, -(long) (sizeof(one)), SEEK_END);
if (res != 0)
{
printf("res = %d\n", res);
perror("Error in seek()");
return -3;
}
printf("(file position: byte #%ld)\n", ftell(f));
if (fread(&one, sizeof(one), 1, f) != 1) return -4;
fclose(f);
return one.id;
}
The lines you want are these:
Applicant one = {0};
fseek(f, SEEK_END, SEEK_SET);
fseek(f, -(long) (sizeof(one)), SEEK_END);
fread(&one, sizeof(one), 1, f);
You go to the end if file, then goes back 1 record and read it.
sample output
5 Ids written to "sample.dat"
now open file and get the last ID used
(file position: byte #16)
Last ID on "sample.dat" is 104
For this
C code
#include <stdio.h>
typedef struct
{ int id;
} Applicant;
int create(const char*,unsigned);
int get_last_id(const char*);
int main(void)
{
const char* f_name = "sample.dat";
const unsigned initial_size = 5;
int res = 0;
// a few ids are written to file
if ( (res = create(f_name, initial_size)) < 0) return -1;
printf("\
%d Ids written to \"%s\"\n\
now open file and get the last ID used\n",
res, f_name);
// get the last id on file
res = get_last_id(f_name);
if (res < 0)
{
printf("Could not get id from file (%d)\n", res);
return -1;
}
else
printf("Last ID on \"%s\" is % d\n", f_name, res);
return 0;
}
int get_last_id(const char* f_name)
{
Applicant one = {0};
int res = 0;
FILE* f = fopen(f_name, "rb+");
if (f == NULL) return -1;
res = fseek(f, SEEK_END, SEEK_SET);
if (res != 0) return -2;
res = fseek(f, -(long) (sizeof(one)), SEEK_END);
if (res != 0)
{
printf("res = %d\n", res);
perror("Error in seek()");
return -3;
}
printf("(file position: byte #%ld)\n", ftell(f));
if (fread(&one, sizeof(one), 1, f) != 1) return -4;
fclose(f);
return one.id;
}
int create(const char* f_name, unsigned int n_rec)
{
Applicant one = {100};
FILE* f = fopen(f_name, "wb");
if (f == NULL) return -1;
for (unsigned i = 0; i < n_rec; i += 1, one.id+= 1)
if (fwrite(&one, sizeof(one), 1, f) != 1)
return 1 + i;
fclose(f);
return n_rec;
}; // create()
```
[1]: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fseek-fseeki64?view=msvc-160

EOF sign in the middle of a textfile [duplicate]

I am writing a XOR encryption program which works fine during encryption but during decryption
the
char ca2=fgetc(f);
gets stuck at one point and no decryption takes place after that my best guess about the problem is (the encrypted file contains all sorts of characters ) as soon as fgetc reaches EOF mark which can be present before the actual end of the file it gets stuck there and stop reading the next characters .
is this some kind of limitation of getc() ? here is my rubbish code
int get_file_size(char filename[])
{
FILE *p_file = NULL;
p_file = fopen(filename,"rb");
fseek(p_file,0,SEEK_END);
int size = ftell(p_file);
fclose(p_file);
return size;
}
int endec(char filename[],char psdw[])
{
FILE *f;
int hashed=0,ed=0;
int inphash=inhash(psdw);
inphash=inphash%50;
f=fopen(filename,"r");
if(f==NULL)
printf("failed");
char temps[999999];
long int crs=0,j=0;
int filesz=get_file_size(filename);
printf("file size = %d\n\n",filesz);
while(1){
inphash=inphash+2;
char ca=(char)inphash;
char ca2=fgetc(f);
printf("%c\n",ca2);
if(crs>=filesz)
break;
temps[crs]= ca2 ^ ca;
crs++;
}
fclose(f);
printf("%d",strlen(temps));
FILE *fp;
fp=fopen(filename,"wt");
for(j=0;j<crs;j++){
putc (temps[j] , fp);
printf("%c",temps[j]);
}
fclose(fp);
}
Your problem is right here:
f=fopen(filename,"r");
You open the file for text reading, not for binary. Your file size function gets it right, but your decoder function does not.
The idiomatic way to read a file character by character using the C-style IO routines is like this:
f = fopen(filename, "rb");
if (!f)
// handle error
int c; // NOTE: int, not char!
while ( (c = fgetc(f)) != EOF )
{
// do something with 'c'
}
This idiom does not require you to get the file size as a separate operation. You can rewrite your XOR "encryption" routine with a simple loop of the above form. It will be much clearer and more concise.
Your entire decoder function could be rewritten as follows: (minus the debug code)
int endec(char filename[], char psdw[])
{
int inphash = inhash(psdw) % 50;
char temp[999999]; // really, should be std::vector<char>
FILE *f;
if ( (f = fopen(filename, "rb")) == NULL )
{
printf("opening for read failed\n");
return -1;
}
size_t crs = 0;
int c;
while ( (c = fgetc(f)) != EOF )
{
inphash += 2;
temp[crs++] = (char)(inphash ^ c);
}
fclose(f);
if ( (f = fopen(filename, "wt")) == NULL )
{
printf("opening for write failed\n");
return -1;
}
if (fwrite(temp, crs, 1, f) != crs)
{
printf("short write\n");
fclose(f);
return -1;
}
fclose(f);
return 0;
}
Not stellar error handling, but it is error handling.

C++ Checksum algorithm for File Transfer

I have been asked to create a checksum algorithm for a file transfer, the C++ code I have been given is as follows:
// ChecksumTestTool.cpp : Defines the entry point for the console
application.
//
#include "stdafx.h"
#include <string>
#include <stdio.h>
#include <iostream>
unsigned long CalculateChecksum(FILE* pFile);
int main(int argc, char *argv[])
{
int result = 0;
//Get filename from command args
std::string fileName;
if (argc >= 1)
{
fileName = argv[0];
//Open file with read access
FILE* pFile = nullptr;
int error = fopen_s(&pFile, fileName.c_str(), "r");
if (error != 0 || pFile == nullptr)
{
printf("Failed to open file with error %d\r\n", error);
result = -1;
}
else
{
//Calculate the checksum
unsigned long checksum = CalculateChecksum(pFile);
printf("Calculated Checksum for %s is %lu (0x%04X)\r\n",
fileName.c_str(), checksum, checksum);
}
}
else
{
printf("Must enter filename on command line\r\n");
result = -1;
}
//Wait here so we can see result
printf("\r\nPress Any Key to Exit\r\n");
getchar();
return 0;
}
unsigned long CalculateChecksum(FILE* pFile)
{
unsigned long checksum = 0;
//TODO:: Calculate the checksum
return checksum;
}
I need to create the checksum at the point '//TODO:: Calculate the checksum'. The algorithm need to check whether the file transfers or not.
So far I have tried:
unsigned long CalculateChecksum(FILE* pFile)
{
unsigned long checksum = 0;
//TODO:: Calculate the checksum
unsigned long word = 0;
while (file.read(reinterpret_cast<char*>(&word), sizeof(word))); {
checksum += word;
}
if (file.gcount()); {
word &= (~0U >> ((sizeof(unsigned long) - file.gcount()) * 8));
checksum += word;
}
return checksum;
}
and I get errors saying 'file' is an undeclared identifier and that left '.gcount' must have class/struct/union
I have searched around for multiple checksums and this algorithm is the only one I found that works within this code
Some things:
you pass a variable called pFile to the function, within the function you use file.
You use if(expression);, therefore the part after the if will always be executed, as the if() has no influence whatsoever.
I didn't even consider whether the checksum function works, but when you do
if(term);
{
// Do something
}
the Do something will always be reached. It should rather be
if (term)
{
// Do something
}
so it will only do it if the term evaluates true

Can't load file using fopen()

I creating a program that takes a file and ecrypts it, but now i'am with a problem opening the file to read, the fopen() always return 0.
void run(){
char buffer[260] = { '\0' };
GetWindowTextA(Path,buffer,260);
encryptFile(buffer, "C:\\Users\\DownD\\Desktop\\Some.dat");
}
I think the problem is somewhere on this function run(), because when replace the buffer array with some string for example, "C:\\Somefile.exe" replacing the function encryptFile() for:
encryptFile("C:\\Somefile.exe", "C:\\Users\\DownD\\Desktop\\Some.dat");.It reads the file nice and clean.
Here it is parts of the rest of the project.
int CCrypter::encryptFile(char* filePath, LPCSTR outFile)
{
unsigned char* data = NULL;
int cypherSize;
int fSize = readFile(data, filePath);
if (!fSize)
return 2;
unsigned char *ciphertext = new unsigned char[fSize];
cypherSize = encrypt(data, fSize, ciphertext);
if (!cypherSize)
return 3;
if (!Create_File(ciphertext, cypherSize, outFile))
return 4;
return 1;
}
int CCrypter::readFile(unsigned char *&buffer, const char* path)
{
int lenght = 0;
OutputDebugString(path);
FILE* input = fopen(path, "rb");
if (!input) // Input is always 0
return 0;
fseek(input, 0, SEEK_END);
lenght = ftell(input);
buffer = new unsigned char[lenght];
printf("%d", buffer);
ZeroMemory(buffer, lenght);
rewind(input);
if (!fread(buffer, 1, lenght, input))
return 0;
fclose(input);
return lenght;
}
Just to clarify, i'm using Multi-Byte Character Set
I solved the issue. The problem was that I had opened the file before and did not close it, that was why I was receiving permission denied.

stack check fail in sha-1 c++

I'm having a __stack_chk_fail in the main thread.
I have no idea why is this happening?
I got the codes from this website:
http://www.packetizer.com/security/sha1/
Im trying to add a function to compute the digest of a file using the example.
.h file
#include <stdio.h>
#include <string>
std::string digestFile( char *filename );
.cpp file
std::string SHA1::digestFile( char *filename )
{
Reset();
FILE *fp = NULL;
if (!(fp = fopen(filename, "rb")))
{
printf("sha: unable to open file %s\n", filename);
return NULL;
}
char c = fgetc(fp);
while(!feof(fp))
{
Input(c);
c = fgetc(fp);
}
fclose(fp);
unsigned message_digest[5];
if (!Result(message_digest))
{ printf("sha: could not compute message digest for %s\n", filename); }
std::string hash;
for (int i = 0; i < 5; i++)
{
char buffer[8];
int count = sprintf(buffer, "%08x", message_digest[i]);
if (count != 8)
{ printf("converting unsiged to char ERROR"); }
hash.append(buffer);
}
return hash;
}
__stack_chk_fail occurs when you write to invalid address.
It turns out you do:
char buffer[8];
int count = sprintf(buffer, "%08x", message_digest[i]);
C strings are NUL-terminated. That means that when sprintf writes 8 digits, it adds 9-th char, '\0'. But buffer only has space for 8 chars, so the 9-th goes past the end of the buffer.
You need char buffer[9]. Or do it the C++ way with std::stringstream, which does not involve any fixed sizes and thus no risk of buffer overrun.