0

I am learning how to write a simple CGI page with C language. I tried with Apache on both Linux and Windows. I compiled my scripts on 2 different computers that run different OSes.


  1. Firstly, I created a simple CGI page for getting a static plain-text content:
    #include 

    int main()
    {
        FILE *fp = fopen("plain_text.txt", "r"); // text-mode only.

        if (fp)
        {
            int ch;

            printf("content-type: text/plain\n\n");

            while ((ch = fgetc(fp)) != EOF)
            {
                printf("%c", ch);
            }

            fclose(fp);
        }

        return 0;
    }

I compiled it into an executable and put it in cgi-bin directory. When I browse it with my web-browser, it returns the plain-text content correctly (both Linux and Windows).


  1. Then, I modified above script for getting a simple JPEG content. (I understand that: every JPEG picture is a binary file)
   #include 

    int main()
    {
        FILE *fp = fopen("cat_original.jpg", "rb"); // with binary-mode.

        if (fp)
        {
            int ch;

            printf("content-type: image/jpg\n\n");

            while (((ch = fgetc(fp)) != EOF) || (!feof(f1))) // can read whole content of any binary file.
            {
                printf("%c", ch);
            }

            fclose(fp);
        }

        return 0;
    }

I compiled it into an executable and put it in cgi-bin directory, too. I can get the correct returned-image with Linux compiled-executable files; but, the Windows does not.


To understand the problem, I downloaded the returned-image with Windows compiled-execute files. (I named this image: cat_downloaded_windows.jpg) Then, I used VBinDiff for compare 2 images: cat_original.jpg (68,603 bytes) and cat_downloaded_windows.jpg (68,871 bytes). There are many lines in cat_downloaded_windows.jpg (like the row I marked) have a character which cat_original.jpg does not have.

VBinDiff

So, I guess that the Windows OS causes the problem (Windows add some characters automatically, and Linux does not) (Apache and web-browsers do not cause problem)


So, I posted this topic into StackOverflow for getting your helps. I have 2 questions:

  1. Is there any problem with the printf("%c", ch); (in my script) on Windows?
  2. Is there any way to print binary content into stdout, both Linux and Windows?

I am learning programming myself, and this is the first time I ask on StakOverflow. So, if my question is not clear, please comment below this question; I will try to explain it more.

Thank you for your time!

1 Answers1

3

When you use printf() to write to standard output, it is working in text mode, not binary mode, so every time your program encounters a newline \n in the JPEG file, it writes \r\n on Windows, which corrupts the JPEG file.

You'll need to know how to put standard output into binary mode and you'll need to ensure that you generate \r\n in place of \n in the headers.

The MSDN documentation says you can use _setmode(), and shows an example (setting stdin instead of stdout):

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

int main(void)  
{  
    int result;  

    // Set "stdin" to have binary mode:  
    result = _setmode(_fileno(stdin), _O_BINARY);  
    if (result == -1)
        perror("Cannot set mode");  
    else  
        printf("'stdin' successfully changed to binary mode\n");  
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • `_setmode` is not a standard library function. –  Feb 07 '18 at 07:29
  • @t2533799: No, of course `_setmode()` isn't standard as defined by ISO 9899 or POSIX. It's a Microsoft function needed to make things work on Microsoft's Windows. But that's the platform where the OP has a problem, so it is appropriate to offer the help there. – Jonathan Leffler Feb 07 '18 at 07:31
  • Yes, `_setmode` is very useful. But, is there alternative way to solve my problem? –  Feb 07 '18 at 07:32
  • I dunno; you'll have to wait for someone else to proffer an alternative solution. I don't know of another way of dealing with binary files written to standard output on Windows. You might find something on a site like — oh, maybe Stack Overflow. I've not tried searching for duplicates yet. – Jonathan Leffler Feb 07 '18 at 07:34
  • Searching SO with '`[c] binary standard output windows`' throws up some candidates: [Portable way to put stdout in binary mode](https://stackoverflow.com/questions/40609260/)—[Why when we write \n in the file it converts into \r\n combination](https://stackoverflow.com/questions/19839883/)—[Is it possible to pass binary data through the console](https://stackoverflow.com/questions/9554252/)—[Simple encryption/decryption algorithm causing EOF](https://stackoverflow.com/questions/28781430/). You may want to follow some of the links from some of the answers to at least some of those questions. – Jonathan Leffler Feb 07 '18 at 07:41
  • I upvoted, but I think it needs to be clarified that this is the behavior of Microsoft C/C++ on Windows, which specifically implements text mode in its low-level POSIX emulation layer. The Windows I/O system has no notion of text mode. It's all just bytes to the OS. – Eryk Sun Feb 07 '18 at 08:43