changed comments in c program and its resulting in segmentatoin fault [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last month.
Improve this question
this the difference between commits, which is just different comments and line spaces, but the old commit runs normally and the new result in a seg fault:
Binary files a/recover/recover and b/recover/recover differ
diff --git a/recover/recover.c b/recover/recover.c
index f0ffdf6..02ab42b 100644
--- a/recover/recover.c
+++ b/recover/recover.c
## -1,34 +1,32 ##
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
typedef enum
{
- false,
- true
-} bool;
+ true,
+ false
-typedef uint8_t BYTE;
+} bool;
typedef char *string;
+typedef uint8_t BYTE;
int BLOCK_SIZE = 512;
int main(int argc, char *argv[])
{
- // Check if a file name was provided as an argument
- if (argc < 2)
+ if (argc != 2)
{
- fprintf(stderr, "Error: No file name provided.\n");
+ fprintf(stderr, "Usage: recover {filename}\n");
return 1;
}
-
- // Open the file for reading
- FILE *raw_file = fopen(argv[1], "r");
+ string fpath = argv[1] == NULL ? "./card.raw" : argv[1];
+ FILE *raw_file = fopen(fpath, "r");
if (raw_file == NULL)
{
- fprintf(stderr, "Error: Could not open file.\n");
+ fprintf(stderr, "Error: filename not valid!\n");
return 2;
}
## -38,33 +36,31 ## int main(int argc, char *argv[])
FILE *img = NULL;
bool opened = false;
- // Read blocks of size BLOCK_SIZE from the file
while (fread(buffer, 1, BLOCK_SIZE, raw_file) == BLOCK_SIZE)
{
- // If start of new JPEG
+ // if start of new jpeg
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
- // If a JPEG file is already open, close it and free the filename
+ // if opened
if (opened)
{
free(fname);
fclose(img);
}
- // Allocate memory for the new filename and create a new JPEG file
+ // opened or not
fname = malloc(sizeof(char) * 8);
sprintf(fname, "%03i.jpg", i);
img = fopen(fname, "w");
opened = true;
i++;
}
- // If a JPEG file is open, write the block to it
+ // if opened jpeg start or not
if (opened)
{
fwrite(buffer, 1, BLOCK_SIZE, img);
}
}
-
- // If a JPEG file is open, close it and free the filename
+ // when gone over entire disk image
if (opened)
{
free(fname);
It's basically the same program just different formatting and comments, it doesn't make sense at all.
I don't any difference or error in the code, if you can, please share with us!
expected: running normally
got: segmentation fault (core dumped)

The statement “It's basically the same program just different formatting and comments” is ludicrous. The commit changes:
false,
true
to:
true,
false
with the result that the values for false and true of 0 and 1, respectively, are changed to 1 and 0, respectively.
The code declares opened to be bool and uses it in if (opened). This obviously uses the wrong sense for opened.

Related

Can't figure out solution to cs50's "Recover" in C. New JPEGs are being created but I cannot view them-

I am currently on the "Recover" pset in cs50 and I have tried multiple variations of my solution. The assignment is to recover 50 JPEG files that were deleted from a memory card. We are instructed to check the first 4 bytes of each 512 byte pass of fread to indicate the start of a JPEG file and to write it to a new file. Once it reaches another 4 bytes that match, we are suppose to close the previous file and write to a new one until reaching EOF (the data from the memory card is provided to us in a file called card.raw).
Below is my current solution. My confusion is that I am able to produce exactly 50 JPEGS upon running my program, as described. However, when I go to open any of the new files, I am met with an error in VS Code, which I will include below my code. Any help would be appreciated here-
`
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
FILE *forensic = fopen(argv[1], "r");
if (forensic == NULL)
{
printf("File was not found\n");
return 1;
}
FILE *currentFile;
currentFile = NULL;
int jpegCount = 1;
char *filename = NULL;
filename = malloc(8 * sizeof(char));
BYTE buffer[512];
while (fread(buffer, sizeof(char), 512, forensic) != 0)
{
// Check for matching 4 bytes, indicating start of a new JPEG
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// If file exists, close it and start a new one
if (currentFile != NULL)
{
fclose(currentFile);
sprintf(filename, "%03i.jpg", jpegCount);
currentFile = fopen(filename, "w");
jpegCount++;
}
// If no file exists yet, create one
else
{
sprintf(filename, "%03i.jpg", jpegCount);
currentFile = fopen(filename, "w");
jpegCount++;
}
}
// If file exists, write to it
if (currentFile != NULL)
{
BYTE wBuffer[512];
fwrite(wBuffer, sizeof(BYTE), 512, currentFile);
}
}
fclose(currentFile);
fclose(forensic);
free(filename);
return 0;
}
`
Again, my program successfully produces 50 new JPEGs, but when I try to open them in VS Code I get the following error:
Error loading webview: Error: Could not register service workers: NotSupportedError: Failed to register a ServiceWorker for scope ('https://0foennjt10in3q0224oduooshmepdo2jsp1eg131ejbmkj7a2i7k.vscode-cdn.net/stable/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/out/vs/workbench/contrib/webview/browser/pre/') with script ('https://0foennjt10in3q0224oduooshmepdo2jsp1eg131ejbmkj7a2i7k.vscode-cdn.net/stable/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/out/vs/workbench/contrib/webview/browser/pre/service-worker.js?v=4&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&remoteAuthority=codespaces+sebdoubleu-code50-111027905-wpxr5g54pv9h9667'): The user denied permission to use Service Worker..
I would really appreciate any help here. I am a beginner and it is very possible that I have made a minor error that I'm not seeing. It is also possible that I am going about this completely wrong and need to start over. I just don't know where to go from here because I feel like I've tried everything that I can think of at this point.

CS50 pset4 recover - Recovered image does not match

I have been trying to do this problem for at least a week now, and can't seem to understand where is the problem, I already checked everything in google, and dont know any programmer in real life to ask them personaly, so if anyone can help me it would be great.
None of the images generated load, and it doesnt recover 50 as it is suposed to, it recovers 986.
I get this results in check50:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:( recovers 000.jpg correctly
recovered image does not match
:( recovers middle images correctly
recovered image does not match
:( recovers 049.jpg correctly
recovered image does not match
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int main(int argc, char *argv[])
{
//it only accepts one comand argument in the name of an image
if (argc != 2)
{
printf("Usage: ./recover IMAGE");
return 1;
}
//check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("The image cannot be opened");
return 1;
}
bool jpg_before = false;
int counter = 0;
FILE *image = NULL;
char name[8];
unsigned char buffer[BLOCK_SIZE];
//while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0)
{
jpg_before = true;
}
if(jpg_before == true)
{
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "a");
fwrite(buffer, BLOCK_SIZE, 1, image);
fclose(image);
}
}
fclose(file);
}
(also please keep in mind I'm new to programming, 16 years old and english is not my first lenguage)
When you detect a header in the input, you set jpg_before. But, you never clear it.
Once the flag is set, each block will be put into a different file.
Every output file should consist of a header, followed by the associated data blocks.
name[8] is a bit too small. The compiler will complain because the int could [in theory] be 10 or so digits, so the sprintf could overflow. Don't be stingy--use (e.g.): char name[20];
Output file should be opened with "w" instead of "a". If the program is run twice, the second time, the output file(s) will be incorrect.
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
printf("The image cannot be opened");
return 1;
}
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "w");
}
fwrite(buffer, BLOCK_SIZE, 1, image);
}
if (image != NULL)
fclose(image);
fclose(file);
}
UPDATE:
From the comments below:
Points 2 and 3 look to be handled by the file being opened for appending. Leaving the file open is probably a better idea, though. Faster and handles point 6. –
user4581301
If H is header and D is data, for an input of (e.g): H1,D1,D2,D3,D4,H2,D5,D6,D7:
Instead of two output files: F0:H1,D1,D2,D3,D4 and F1:H2,D5,D6,D7
We'd have: F0:H1, F1:D1, F2:D2, F3:D3, F4:D4, F5:H2, F6:D5, F7:D6, F8:D7
Although my refactored code was correct, the top section of my answer had an incorrect analysis of what OP's code was actually doing.
I've fixed that. But, to make user4581301's make sense, here is the original analysis:
When you detect a header in the input, you set jpg_before. But, you never clear it.
You only write to the output stream for the header block, so any data is not copied. So, each output file will only be 512 bytes
You immediately close the output stream after writing the header. It should be left open.
Every block must go to a given output file, not just the header.
name[8] is a bit too small. The compiler will complain because the int could [in theory] be 10 or so digits, so the sprintf could overflow. Don't be stingy--use (e.g.): char name[20];
Output file should be opened with "w" instead of "a". If the program is run twice, the second time, the output file(s) will be incorrect.
UPDATE #2:
First of all thanks! But it is giving me a segmentation fault, do you have any idea why? because everything seems correct –
Isa M
From code inspection, the only place that could segfault is the fwrite call (i.e. image is NULL).
I confirmed this by running the program under gdb [I have the cs50 recover input file]. When the program faults, just do tb to get a stack traceback.
image could be NULL for the following reasons:
The fopen for output file could fail (due to permissions, space, etc.) and return NULL. There was no check after the call as there was for opening the input file.
image starts out being NULL. If there is some sort of extra file data/file header before the first jpg header (e.g. before FF/D8/FF/E0) the if will not match on the first block read. The fwrite will be called even with a NULL in image.
Option (2) is what actually occurred because cs50's file has an extra header at the top of the file. You can see this by examining the file with a hex editor/dumper (e.g.) od or xxd:
00000000: 00000000 00000000 00000000 00000000 ................
*
00000200: 63733530 2E6C792F 73757270 72697365 cs50.ly/surprise
00000210: 00000000 00000000 00000000 00000000 ................
*
00000400: FFD8FFE0 00104A46 49460001 01000001 ......JFIF......
The code will not see a valid header (i.e. the if matches) until offset 400. So, there are two extraneous fread calls at the start until things sync up.
The fix is to change:
fwrite(buffer, BLOCK_SIZE, 1, image);
Into:
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
I've written a few answers on this problem before. However, I forgot to include this. I just wrote the code but did not test it ;-)
To round things out, I've added more return code checking and added "rb" and "wb" to the fopen calls, just in case you're running on Windoze.
Here is the updated/fixed code (I've tested it this time ;-):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
void
onerr(const char *action,const char *file)
{
printf("%s -- %s -- %s\n",action,file,strerror(errno));
exit(1);
}
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "rb");
if (file == NULL)
onerr("The image cannot be opened",argv[1]);
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "wb");
if (image == NULL)
onerr("unable to open output file",name);
}
#if 0
fwrite(buffer, BLOCK_SIZE, 1, image);
#else
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
#endif
}
if (image != NULL)
fclose(image);
fclose(file);
return 0;
}

CS50 Problem set 4 Recover not recovering images

I could do with some advice for this, to me this makes sense logically however when I run check50 only one of the images are recovered. I've looked through the code multiple times so I don't think its a syntax error so it must be some error with the logic. Any tips would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cs50.h>
typedef uint8_t BYTE;
bool is_jpeg_header(BYTE buffer[]);
int main(int argc, char *argv[])
{
// Check if command line argument is valid
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
// Open memory card files
char* mem_card = argv[1];
FILE* inptr = fopen(mem_card, "r");
if (inptr == NULL)
{
printf("File not found/n");
return 1;
}
BYTE buffer[512];
bool found_first_jpeg = false;
int image_count = 0;
char filename[8];
FILE* outptr = NULL;
while (!feof(inptr) && fread(buffer, sizeof(buffer), 1, inptr) == true)
{
// Check if we have found a JPEG
if (is_jpeg_header(buffer) == true)
{
// Check if this is the first JPEG
if (found_first_jpeg == false)
{
found_first_jpeg = true;
sprintf(filename, "%03i.jpg", image_count);
outptr = fopen(filename, "w");
fwrite(buffer, sizeof(buffer), 1, outptr);
image_count++;
}
// If this isn't the first JPEG, close file current JPEG and open new one for new JPEG
else
{
fclose(outptr);
image_count++;
sprintf(filename, "%03i.jpg", image_count);
outptr = fopen(filename, "w");
}
}
// If we haven't found a new JPEG:
else if (is_jpeg_header(buffer) == false)
{
// Continue reading file if we have not found first JPEG
if (found_first_jpeg == false)
{
continue;
}
// Continue writing current JPEG into current file
else
{
fwrite(buffer, sizeof(buffer), 1, outptr);
}
}
}
fclose(inptr);
fclose(outptr);
return 0;
}
bool is_jpeg_header(BYTE buffer[])
{
if (((buffer[0] == 0xff) && (buffer [1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0)))
{
return true;
}
return false;
}
This is the error code I receive from check50
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:) recovers 000.jpg correctly
:( recovers middle images correctly
001.jpg not found
:( recovers 049.jpg correctly
recovered image does not match
One bug I see is that filename is too short: you haven't left any room for the terminating zero. That's undefined behavior, and likely your source of trouble.
But the logic overall is very convoluted for what amounts to a simple problem. Here's how I'd write it. Since you're not in general checking for errors, I've left it that way - it's likely OK for this test assignment, although I've not read it. It does help to return different error codes for different errors though - it'd have really helped with the original typo!
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint8_t bool;
static const bool true = 1;
static const bool false = 0;
bool is_jpeg_header(const uint8_t buffer[]);
int main(int argc, char *argv[])
{
// Check if command line argument is valid
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
// Open the memory card image
char* mem_card = argv[1];
FILE* infile = fopen(mem_card, "r");
if (!infile)
{
printf("File not found/n");
return 2;
}
uint8_t buffer[512];
int image_count = 0;
char filename[9];
FILE* outfile = NULL;
while (!feof(infile) && fread(buffer, sizeof(buffer), 1, infile) == 1)
{
// Check if we have found a JPEG
if (is_jpeg_header(buffer))
{
// If we're already writing output - close it
if (outfile)
fclose(outfile);
sprintf(filename, "%03i.jpg", image_count);
outfile = fopen(filename, "w");
image_count ++;
}
// Write the output if we're ready to write
if (outfile)
fwrite(buffer, sizeof(buffer), 1, outfile);
}
fclose(infile);
fclose(outfile);
return 0;
}
bool is_jpeg_header(const uint8_t buffer[])
{
return
buffer[0] == 0xff
&& buffer[1] == 0xd8
&& buffer[2] == 0xff
&& (buffer[3] & 0xf0) == 0xe0;
}
why while(!foef() is always wrong
regarding:
printf("File not found/n");
Error messages should be output to stderr, not stdout.
When the error indication comes from a C library function should also output to stderr, the text reason the system thinks the error occurred. The function:
perror( "your error msg" );
is made for this purpose.
regarding:
printf("Usage: ./recover image\n");
1) this should be to stderr, not stdout. 2) don't hardcode the executable name. Suggest:
fprintf( stderr, "Usage: %s imagefile\n". argv[0] );
regarding:
while (!feof(inptr) && fread(buffer, sizeof(buffer), 1, inptr) == true)
1) true and false are defined in stdbool.h so that header file needs to be included.
2) fread() returns the number of items read. (which is also the third parameter, (and remembering the prior statement about while( !foef() ) so the statement would be much better written as:
while ( fread(buffer, sizeof(buffer), 1, inptr) == 1)
which catches EOF and partial reads and I/O errors.
regarding;
outptr = fopen(filename, "w");
The success/failure of the call to fopen() is not under the control of your program, Therefore, always check (!=NULL) the returned value to assure the operation was successful.
regarding:
if (is_jpeg_header(buffer) == false)
{ // Continue reading file if we have not found first JPEG
if (found_first_jpeg == false)
{
continue;
} // Continue writing current JPEG into current file
else
This code can be completely removed
the posted code fails to close the current output file after the second file is started.
the posted code always reads sizeof(buffer) bytes (assuming no errors) but there is no guarantee that each image data is exactly a multiple of sizeof(buffer) in length so it can miss the encounter with the next image AND can result in part of the header, etc data from the next image being written into the current output file.
Please post the function:
is_jpeg_header(buffer)
as it is unlikely to correct the problems listed above.

Pset4 (cs50) recover does not work properly. It compiles, but does not recover more than 2 jpegs. Is something wrong with checking for JPEG signature?

I am learning how to code and I have no experience with that at all. I've successful got to PSET4 and stuck on recover. I've read everything online about this problem and i found out that many people have similar code as I do and it works. Does not work for me whatsoever. Please have a look and give me a hint what did I do wrong and how to correct it.
Here is everything about the pset4 recover i downloaded their card.raw from here card.raw
/** recovering JPEG files from a memory card
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr,
"Usage: ./recover infile (the name of a forensic image from which to recover JPEGs)\n");
return 1;
}
// open input file (forensic image)
FILE* inptr = fopen(argv[1], "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
FILE* outptr = NULL;
// create a pointer array of 512 elements to store 512 bytes from the memory card
BYTE* buffer = malloc(sizeof(BYTE) * 512);
if (buffer == NULL)
{
return 3;
}
// count amount of jpeg files found
int jpeg = 0;
// string for a file name using sprintf
char filename[8] = { 0 };
// read memory card untill the end of file
while (fread(buffer, sizeof(BYTE) * 512, 1, inptr) != 0)
{
// check if jpeg is found
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff
&& (buffer[3] >= 0xe0 || buffer[3] <= 0xef))
{
if (jpeg > 0)
{
fclose(outptr);
}
sprintf(filename, "%03d.JPEG", jpeg);
outptr = fopen(filename, "w");
jpeg++;
}
if (jpeg > 0)
{
fwrite(buffer, sizeof(BYTE) * 512, 1, outptr);
}
}
// free memory
free(buffer);
// close filename
fclose(outptr);
// close input file (forensic image)
fclose(inptr);
return 0;
}
The main problem is that you invoke undefined behavior because filename is not enough big. sprintf() need be 9 and 17 bytes with your code but you only has 8. So you have a buffer overflow.
Just change:
char filename[8] = { 0 };
to
char filename[17] = { 0 };
Because, you use an int, this value is implemented defined but in many system has an int with 32 bits. So the value possible are between -2^31 and 2^31 - 1 that make a maximum of 11 chars (-2147483648). We add the number of chars in ".JPEG", 5. We have 16 but you forget the null terminate byte of a c-string. So we are 17 maximum.
Modern compiler warning you: gcc version 7.1.1 20170516 (GCC):
In function ‘main’:
warning: ‘sprintf’ writing a terminating nul past the end of the destination [-Wformat-overflow ]
sprintf(filename, "%03d.JPEG", jpeg++);
^
note: ‘sprintf’ output between 9 and 17 bytes into a destination of size 8
sprintf(filename, "%03d.JPEG", jpeg++);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plus, your typedef is useless because a char world be always a byte in C. More than that you don't need a byte but an octet so like char, uint8_t would be always an octet in C. So you don't need typedef.
Again one thing, you allocate your buffer but it's useless because your buffer has a constant size. So just create an array is more simple.
#include <stdint.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: ./recover infile (the name of a forensic image "
"from which to recover JPEGs)\n");
return 1;
}
FILE *inptr = fopen(argv[1], "r");
if (inptr == NULL) {
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
FILE *outptr = NULL;
uint8_t buffer[512];
size_t const buffer_size = sizeof buffer / sizeof *buffer;
size_t jpeg = 0;
while (fread(buffer, sizeof *buffer, buffer_size, inptr) == buffer_size) {
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff &&
buffer[3] == 0xe0) {
if (outptr != NULL) {
fclose(outptr);
}
char filename[26];
sprintf(filename, "%03zu.JPEG", jpeg++);
outptr = fopen(filename, "w");
}
if (outptr != NULL) {
fwrite(buffer, sizeof *buffer, buffer_size, outptr);
}
}
if (outptr != NULL) {
fwrite(buffer, sizeof *buffer, buffer_size, outptr);
}
if (outptr != NULL) {
fclose(outptr);
}
fclose(inptr);
}
Note: This example is clearly not perfect, this will be better to make a true parser for jpeg file to have a better control flow. Here we suppose that all gonna be right.
how do you know that an instance of a JPEG image will always end with '\n'? Or better, how do you know that a JPEG image will be an exact multiple of 512?
You dont know.
So the posted code needs to calculate the actual value OR use some method to have the last call to fread() for any specific JPEG instance, to stop reading at the end of that image,
Then the check for the ID bytes of the next JPEG image will find the next image.
Otherwise, the start of the next image is already written to the prior output file and the check for a new image will fail.
In general this will result in the last created file containing more than one image.
This link: 'https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format' is a web page that describes the format of a JPEG file.
On every digital camera that I have used, the SD card has a directory of all the files.
Suggest using that directory and the info in the linked web page to find each JPEG image and to determine when the end of that image has been encountered. (I.E. the 0xFF 0xD9)

Programme recovers JPEGs from card but does not pass the CS50 check (pset4)

Hey all mighty programmers, the recover programme seems to work perfectly. I've read other post ... have Valgrind run and it shows no leaks. I have all the 50 pictures from 000 to 049. So, I'm out of ideas. Do you guys have any? Sorry for my wordy comments, but I need to track what happens very literally.
erreor message HERE (click)
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
//fix the name of the file we need to recover from
#define NAME_RAW_FILE "card.raw"
//block size is 512
#define BLOCK_SIZE 512
// "jpg.000" + /n => 8 chars
#define JPEG_NAME_LENGTH 8
// Format of the jpeg file name, using 3 integers padded with 0's
// see https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
#define JPEG_FILE_FORMAT "%03d.jpg"
// bool checking if the header is the one of a jpg
bool is_jpeg (unsigned char header [])
{
/* this is equivalent to saying if(condition), return TRUE. Return gives back to the function
* any value that comes out of the expression in its scope, in our case the value is TRUE if the
* expression with the equivalences is verified, else false. */
return (header[0] == 0xff
&& header[1] == 0xd8
&& header[2] == 0xff
&& (header[3] & 0xf0) == 0xe0);
}
int main(int argc, char *argv[])
{
if (argc != 1)
{
//no command line argument after programme name
fprintf(stderr, "Usage: ./recover\n");
return 1;
}
// open memory card file
FILE* raw_file = fopen(NAME_RAW_FILE, "r");
if (raw_file == NULL)
{
fprintf(stderr, "Could not open file %s.\n", NAME_RAW_FILE);
return 1;
}
// Store new JPG name and count them
char jpeg_filename[JPEG_NAME_LENGTH];
int jpeg_recoverd_counter = 0;
// Currently opened file we're writing to
FILE* jpeg_file = NULL;
/* we need another buffer to store our jpg data from card.raw
* we use unsigned chars because it's basically equivalent to
* saying bytes */
unsigned char buffer [BLOCK_SIZE];
/* loop over every block of the memory card until EOF.
* What this loop does is checking if the fread function
* returned 512 bytes of size 1, and breaks
* when there is a block of less than 512 bytes : end of file */
while (fread (buffer, 1, BLOCK_SIZE, raw_file) == BLOCK_SIZE)
{
// checks if the first 4 bytes of the block corresponds to a jpg
if (is_jpeg (buffer))
{
// Is there a previous jpg file open? If so, close it.
// This won't close your first jpg file which is set to NULL
// at line 43.
if (jpeg_file != NULL)
{
fclose(jpeg_file);
}
// This line creates a custom filename that will be stored
// in the jpeg_filename array
sprintf(jpeg_filename, JPEG_FILE_FORMAT, jpeg_recoverd_counter++);
// Now that I have the name of the file stored in jpeg_filename
// I open a file in reading and writing mode with that name
jpeg_file = fopen(jpeg_filename, "w+");
// Check that jpeg_file opened successfully
if(jpeg_file == NULL)
{
fclose(raw_file);
fprintf(stderr, "recover: %s: Error creating file", jpeg_filename);
return 1;
}
}
/* At this stage, if no jpeg was found then no jpeg_file was opened.
* so I create a condition to skip any initial bytes not belonging to
* a jpeg by checking if there is a jpeg_file open. If we do have a jpeg
* file open, then write into it */
if (jpeg_file != NULL)
{
/* So, if I do have a jpeg file opened, then I want to write into it
* but I also want to make sure that the writing succeeds, so I encase
* fwrite function in a if condition that checks the return value of the
* function (BLOCK_SIZE). If the writing did not succeed then close everything
* and print error. */
if(fwrite(buffer, 1, BLOCK_SIZE, jpeg_file) != BLOCK_SIZE)
{
fclose(jpeg_file);
fclose(raw_file);
fprintf(stderr, "recover: %s : Error writing the file\n", jpeg_filename);
return 1;
}
}
}
// Close last file open, checking that we ever opened one (imagine card.raw had no jpeg!)
if(jpeg_file != NULL)
{
fclose(jpeg_file);
}
// Was there an error reading from the card?
if(ferror(raw_file))
{
fclose(raw_file);
fprintf(stderr, "recover: %s: Error reading file\n", argv[0]);
return 1;
}
// Else, all good.
fclose(raw_file);
return 0;
}

Resources