我正在学习如何编码,而我根本没有这方面的经验。我成功上了PSET4并坚持恢复。我已经在网上阅读了关于这个问题的所有内容,我发现许多人的代码与我一样,并且有效。对我来说不起作用。请看看并给我一个提示我做错了什么以及如何纠正它。 以下是关于pset4的一切recover我从这里下载了他们的card.raw 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;
}
答案 0 :(得分:1)
主要问题是您调用未定义的行为,因为filename
不够大。 sprintf()
需要9和17个字节的代码,但你只有8个。所以你有一个缓冲区溢出。
只需改变:
char filename[8] = { 0 };
到
char filename[17] = { 0 };
因为您使用的是int
,所以此值已定义,但在许多系统中有{32}的int
。因此,可能的值介于-2^31
和2^31 - 1
之间,最多可以生成11 char
s(-2147483648)。我们在“.JPEG”,5中添加char
s的数量。我们有16但是你忘记了c字符串的空终止字节。所以我们最多只有17岁。
现代编译器警告你:gcc版本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++);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
另外,你的typedef
没用,因为char
世界总是C中的一个字节。不仅如此,你不需要一个字节而是一个八位字节,就像char
一样,{ {1}}将始终是C中的八位字节。因此您不需要uint8_t
。
还有一件事,你分配你的缓冲区,但它没用,因为你的缓冲区有一个恒定的大小。所以只需创建一个数组就更简单了。
typedef
注意:这个例子显然不是很完美,这样可以更好地为jpeg文件制作一个真正的解析器,以获得更好的控制流。在这里,我们认为一切都会正确。
答案 1 :(得分:0)
你怎么知道JPEG图像的实例总是以'\ n'结尾?或者更好的是,你怎么知道JPEG图像将是512的精确倍数?
你不知道。因此,发布的代码需要计算实际值或使用某种方法对任何特定JPEG实例进行最后一次fread()
调用,以停止在该图像末尾读取,
然后检查下一个JPEG图像的ID字节将找到下一个图像。
否则,下一个图像的开头已经写入先前的输出文件,并且检查新图像将失败。
通常,这将导致最后创建的文件包含多个图像。
此链接:“https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format”是一个描述JPEG文件格式的网页。
在我使用的每台数码相机上,SD卡都有一个包含所有文件的目录。
建议使用该目录和链接网页中的信息查找每个JPEG图像,并确定何时遇到该图像的结尾。 (I.E. 0xFF 0xD9)