Home > Software design >  CS50 recover.c Need explanation on file creation
CS50 recover.c Need explanation on file creation

Time:09-09

I watched the solution online and one detail didn't appear clear to me,
Which specific command line does the job of creating the jpg files?
I suppose nothing else other than sprintf could do that, but how exactly it does that?
As far as I'm aware it olny prints the name of the file into location but doesn't create it

int main(int argc, char *argv[])
{
  FILE *raw_file = fopen(argv[1], "r");
  if (raw_file == NULL)
  {
       printf("Could not open file");
      return 1;
  }
  unsigned char buffer[512];
  int count = 0;
  FILE *output = NULL;
  char *filename = malloc(8);

  while (fread(buffer, 1, 512, raw_file) == 512)
  {
    if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
    {
      sprintf(filename, "i.jpg", count);
      output = fopen(filename, "w");
      count  ;

    }
    if (output != NULL)
    {
        fwrite(buffer, 1, 512, output);
    }
  }
  free(filename);
  fclose(output);
  fclose(raw_file);

  return 0;
}

CodePudding user response:

Which specific command line does the job of creating the jpg files?

Typically we call these "lines of [C] code". The term "command line" usually refers to commands as whole programs running on a terminal (or "console"). There are actually two lines of code responsible for creating the jpg file here. The first is:

output = fopen(filename, "w");

This creates a file for writing. But at this point it is empty as it does not hold any data content. filename is the just the name of the file to be created. A reference to a memory where you can write the data is returned by fopen and assigned to output variable.

The contents of the file are written in this line:

fwrite(buffer, 1, 512, output);

In which the source of data to be written is given by the buffer variable. This points to the data read from the raw file with fread above.

I suppose nothing else other than sprintf could do that, but how exactly it does that?

The sprintf here is just writing a filename, assigning it to variable filename. These will be "000.jpg", "001.jpg", "002.jpg" and so on.

'fwrite' does not write directly to the disk as this would be very inefficient. It instead writes the data to a buffer memory (called stream). In order to ensure the stream is flushed to the disk, the following line is called (it probably should be called inside the loop before opening a new output file):

fclose(output);

When the raw file is being read, note that there is some check of its contents in place:

if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)

0xFF 0xD8 is the "Start Of Image" JPEG marker. Used here as a way to ensuring/detecting that the source (raw) file segment actually does hold JPEG data. Have a look at the "Common JPEG markers" table in the JPEG Wikipedia page.

It's recommended to add the 'b' character (denoting "binary") to the fopen function when dealing with binary data, as suggested in the comments. For instance as explained in this fopen manual:

   The mode string can also include the letter 'b' either as a last
   character or as a character between the characters in any of the
   two-character strings described above.  This is strictly for
   compatibility with C89 and has no effect; the 'b' is ignored on
   all POSIX conforming systems, including Linux.  (Other systems
   may treat text files and binary files differently, and adding the
   'b' may be a good idea if you do I/O to a binary file and expect
   that your program may be ported to non-UNIX environments.)
  • Related