1

Platform : Windows

Language : C

I have two programs:

  • Program 1 reads .jpg file in binary mode(_setmode(_fileno(stdin), _O_BINARY) ,_setmode(_fileno(stdout), _O_BINARY) using fread and outputs the using fwrite to stdout.
  • Program 2 reads from stdout and outputs to a file( read/write done in binary mode). But I can see that output image is corrupted and not same as input. I executed program1.exe | program2.exe in powershell.

But if I write a program to read a file in binary mode and write it to another file in binary mode, then outputs are same. Problem occurs only when I use stdin and stdout.

Program 1:

int main()
{
    int mode, fd, ret;
    errno_t err;
    int a = _setmode(_fileno(stdin), _O_BINARY);
    a = _setmode(_fileno(stdout), _O_BINARY);
    //freopen("ooo", "wb", stdout);
    //char in[4096];
    char in[4096];
    char o[100];
    int size = sizeof(in);
    FILE* fpIn, * fpOut, * fp3, * fin;
    //int  a =_setmode(_fileno(stdin), _O_BINARY);
    int x = sizeof(in);
    fpOut = fopen("out", "wb");
    //int bb = _setmode(_fileno(fpOut), _O_BINARY);
    fin = fopen("pic.jpg", "rb");
    //fin = fopen("in.txt", "rb");
    //a = _setmode(_fileno(fin), _O_BINARY);
    //int length = fread(&in, sizeof(in), 1, stdin);
    int count = 0;
    
    while ((count = fread(in, 1, sizeof(in), fin)) != 0)
    {
        fwrite(in, 1, count, stdout);
        fflush(stdout);
    }
    fclose(fpOut);  
}

Program 2:

int main()
{
int a = _setmode(_fileno(stdin), _O_BINARY);
     a = _setmode(_fileno(stdout), _O_BINARY);
    //freopen("ooo.txt", "wb", stdin);
    char in[4096];
    
    int o[100];
    int size = sizeof(in);
    FILE* fpIn, * fpOut, *fp3,*fin;
    //int  a =_setmode(_fileno(stdin), _O_BINARY);
    int x = sizeof(in);
    fpOut = fopen("out", "wb");
    //int bb = _setmode(_fileno(fpOut), _O_BINARY);
    fin = fopen("pic.jpg", "rb");
    a = _setmode(_fileno(fin), _O_BINARY);
    //int length = fread(&in, sizeof(in), 1, stdin);
    int count=0;

    while ((count = fread(in, 1, sizeof(in), stdin)) != 0)
        fwrite(in, 1, count, fpOut);


    fclose(fpOut);
}

The requirement of program is to allow user to input arbitrary input through stdin and write it to a file.

Ynjxsjmh
  • 28,441
  • 6
  • 34
  • 52
Brain
  • 11
  • 1
  • Does `while( ( c = fgetc(stdin) ) != EOF ) { fputc(c, stdout); }` not work? I'm so glad I don't have to work with Windows. – William Pursell Aug 21 '20 at 12:48
  • In program 2, you don’t need to futz with stdout or open fpIn. – Jonathan Leffler Aug 21 '20 at 12:53
  • (1) all that commented-out code is confusing. Paste the code you actually used to produce the results you describe. (2) many compilers complain if you ignore the return value of a system library function. You can suppress the warning by assigning the value to a variable you never use but that's not the point: the point is to make sure the function did not indicate an error, and do something (at a minimum, log the error) if it did. Particularly if you suspect the result. – rici Aug 21 '20 at 14:31

1 Answers1

1

EDIT

Added to address conversation in comments as its relevance may be important to OP. Paying attention to the current encoding settings of your cmd.exe program may be important to do some of the things you are asking for. That topic is discussed in in this very detailed answer. and serve to explain why you are seeing what you are seeing.

Your only stated requirement is "The requirement of program is to allow user to input arbitrary input through stdin and write it to a file."

An example using fread and fwrite is at bottom, but unless you are required to use these, consider a simpler approach...

Borrowing from the comments, this example is the simplest implementation that does exactly what you described you needed. (And was tested using Windows-10.)

<ctrl-c> to exit, then read file out.txt...

int main(int argc, char *argv[]) {

    int c = 0;
    FILE *fp = fopen(".\\out.txt", "w");
    if(fp)
    {
        while( ( c = fgetc(stdin) ) != EOF ) 
        { 
            fputc(c, stdout); //out to screen
            fputc(c, fp); //to file
        }
        fclose(fp);    
    }
    return 0;
}

Reading and outputting a binary file is just about as simple, just change the arguments in fopen() for binary read/write, and point to an image you want to transfer:

No need of course to use <cntl-c>, program will exit when file copy is done.

int main(int argc, char *argv[]) {

    int c = 0;
    FILE *fpIn = fopen(".\\so_1.jpg", "rb");
    FILE *fp = fopen(".\\out.jpg", "wb");
    if(fp)
    {
        while( ( c = fgetc(fpIn) ) != EOF ) { fputc(c, fp); }
        fclose(fp);    
    }
    return 0;
}

If it is required that you use fread/fwrite, then here is a very minimal example of doing exactly the same task using your code with some modifications: (removed calls to setmode, in buffer sized to file it will contain, removed while loop, see in-code comments.)

int main(int argc, char *argv[]) 
{
    int count = 0;
    unsigned long len = fsize(".\\so_1.jpg");//start by getting in file size
    char in[len];//create buffer with exact count of bytes in file
    FILE *fpIn = fopen(".\\so_1.jpg", "rb");
    if(fpIn)
    {
        FILE *fpOut = fopen(".\\out.jpg", "wb");
        if(fpOut)
        {
            count = fread(in, 1, sizeof(in), fpIn);//no need for while loop here, just check for > 0 
            if(count > 0)
            {
                fwrite(in, 1, count, fpOut);
            }
            fclose(fpOut);
        }
        fclose(fpIn);
    }
    return 0;
}

unsigned long fsize(char* file)
{
    if(!file) return 0UL;
    FILE * f = fopen(file, "r");
    if(!f) return 0UL;
    if(fseek(f, 0, SEEK_END) != 0) return 0UL;
    unsigned long len = (unsigned long)ftell(f);
    fclose(f);
    return len;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Thanks for your reply. I want to write arbitary data from STDIN, these will be no problem when so_1.jpg is read and writted to out.jpg, but when I pass these same input through STDIN then the output wont match. consider simple example, when you try to write ☻(ALT + NUMKEY2) as input to STDIN the out.txt won't contain ☻ instead it will contain some invalid char or no char( due to difference in encoding), same can be observed with some.jpg as input through stdin – Brain Aug 21 '20 at 16:34
  • @Brain - keep in mind that the there are many more binary combinations of bits in an `unsigned char` ( `byte`) than are representable within the printable character range visible in `stdout`. Plainly stated, text streams may be encoded in several ways, but binary data is binary data. Your example inputs a text representation of `☻(ALT + NUMKEY2)`, but it can be [encoded in more than one way](https://www.puredevsoftware.com/blog/2017/11/17/text-encoding/), (eg `ASCII`, `unicode`, `wide char`) each one leading to a corresponding and different binary stream. That may be why `input != output` – ryyker Aug 21 '20 at 16:46
  • `ASCII A` encoding for example is `0x41`, while `EBCDIC` encoding is `0xC1` resulting in different binary values. See updated note at top of my answer. – ryyker Aug 21 '20 at 20:22