Sunday 2 June 2019

Error with binary-writting mode with C, on Windows?



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!


Answer



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 
#include
#include

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");
}

No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...