Reputation: 13758
I was playing with very simple encryption/decryption algorithm like this;
#include <stdio.h>
#include <stdlib.h>
#define BUFFESIZE 1024
int main(int argc, char *argv[]) {
int keylen = 0;
char *key = argv[1];
char *buffer = NULL;
size_t buffersize = 0;
size_t nbytes = 0;
size_t nread;
int i = 0;
while(*key++ != 0) keylen++;
key = argv[1];
do {
buffersize+=BUFFESIZE;
buffer = realloc(buffer, buffersize);
nread = fread(buffer+nbytes, 1, BUFFESIZE, stdin);
nbytes+=nread;
} while (nread > 0);
for(i=0; i<nbytes; i++) {
putchar(buffer[i] ^ key[i % keylen]);
}
return 0;
}
Encyption key is the first command-line argument to the program. I expect that this should get me originial file when encrypted/decrypted with same key. However, I sometimes get only small amount of the file back if I encrypt/decrypt it. My guess is that algorithm adds EOF control character in the middle of file.
How can I get around this problem?
I compiled this using MinGW gcc 4.8.1 on windows XP. If you're interested, you can find a sample input file demonstrating the problem in the edit history of this question.
Upvotes: 1
Views: 424
Reputation: 50368
Well, your code works for me on Linux (compiled with GCC 4.8.2), even using your sample input and key. This suggests that the issue is specific to Windows — most likely, that it's caused by stdin and stdout being in text mode by default. (On Linux and other Unix-ish systems, there's usually no difference between text mode and binary mode, so such issues do not show up there.)
To fix it, you will need to set stdin and stdout to binary mode. The standard way of doing this, as of C99, would be:
freopen(NULL, "rb", stdin);
freopen(NULL, "wb", stdout);
but alas, according to the answers in the thread I linked to above, the Windows C library does not support this C99 feature, so you'll need to fall back on the non-standard _setmode()
instead:
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
If you want to remain portable, you could always use some conditional code, e.g. like this (warning: not actually tested on Windows!):
#if __STDC_VERSION__ >= 199901L
#define binmode(fh, w) freopen(NULL, ((w) ? "wb" : "rb"), (fh)) /* C99 */
#elif _MSC_VER >= 1200
#include <io.h>
#include <fcntl.h>
#define binmode(fh, w) _setmode(_fileno(fh), _O_BINARY) /* MSVC 6.0+ */
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#define binmode(fh, w) /* Unix-ish, just do nothing */
#else
#error Not sure how to define binmode() on this platform
#endif
binmode(stdin, 0);
binmode(stdout, 1);
Or, of course, you could just sidestep the whole issue by opening your own input and output files (in binary mode) instead of using stdin
and stdout
.
Upvotes: 2