TL;DR: Why does freopen(NULL, "rb", stdin) always fail on Windows?
I'm trying to re-implement a base64 encoder in C that takes input from stdin and outputs the encoded equivalent into stdout. I had a problem in my previous post where fread was signalling EOF prematurely. Here is what my main method looks like:
int main(void)
{
    unsigned char buffer[BUFFER_SIZE];
    unsigned char base64_buffer[BASE64_BUFFER];
    while (1)
    {
        TRACE_PUTS("Reading in data from stdin...");
        size_t read = fread(buffer, 1, sizeof(buffer), stdin); /* Read the data in using fread(3) */
        /* Process the buffer */
        TRACE_PRINTF("Amount read: %zu\n", read);
        TRACE_PUTS("Beginning base64 encode of buffer");
        size_t encoded = base64_encode(buffer, read, base64_buffer, sizeof(base64_buffer));
        /* Write the data to stdout */
        TRACE_PUTS("Writing data to standard output");
        ...
        if (read < sizeof(buffer))
        {
            break; /* We reached EOF or had an error during the read */
        }
    }
    if (ferror(stdin))
    {
        /* Handle errors */
        fprintf(stderr, "%s\n", "There was a problem reading from the file.");
        exit(1);
    }
    puts(""); /* Output a newline before finishing */
    return 0;
}
Essentially, it reads in data from stdin using fread, encodes to base64, writes it to stdout, then checks if EOF has been reached at the end of the loop.
When I piped the contents of a binary file to this app's stdin, it would only read a fraction of the total bytes in the file. For example:
$ cat /bin/echo | my_base64_program >/dev/null # only view the trace output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 569
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
$ cat /bin/echo | wc -c
28352
As you can see /bin/echo is 28352 bytes long, but only ~2400 of them are being processed. I believe the reason is because stdin is not being considered a binary file, so certain control characters (like Control-Z as mentioned in the linked post's answer) were prematurely signalling EOF.
I took a look at the base64 source code and it looks like they're using xfreopen (which is just a wrapper for freopen) to tell fread to interpret stdin as binary. So I went ahead and did that before the while-loop:
if (!freopen(NULL, "rb", stdin))
{
    fprintf(stderr, "freopen failed. error: %s\n", strerror(errno));
    exit(1);
}
However, now my app always exits at that point with:
$ cat /bin/echo | my_base64_program
freopen failed. error: Invalid argument
So why is freopen at that point failing, when it works for base64? I'm using MinGW-w64 with GCC on Windows if that's relevant.
 
     
    