summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/file_jpg.c128
-rw-r--r--src/file_tiff.c488
-rw-r--r--src/file_tiff.h56
4 files changed, 515 insertions, 159 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2bc8c27..3390015 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@ fs_H = analyse.h bfs.h bsd.h cramfs.h fat.h fatx.h ext2.h jfs_superblock.h jfs
testdisk_SOURCES = testdisk.c $(base_C) $(base_H) $(fs_C) $(fs_H) testdisk.h adv.c adv.h dir.c dir.h dirpart.c dirpart.h diskacc.c diskacc.h edit.c edit.h ext2_dir.c ext2_dir.h ext2_inc.h ext2_sb.c ext2_sb.h fat1x.c fat1x.h fat32.c fat32.h fat_adv.c fat_adv.h fat_dir.c fat_dir.h geometry.c godmode.c godmode.h intrface.c diskcapa.c diskcapa.h intrface.h ntfs_adv.c ntfs_dir.c ntfs_dir.h ntfs_fix.c ntfs_inc.h rfs_dir.c rfs_dir.h $(ICON_TESTDISK) next.c next.h dimage.c dimage.h ntfs_udl.c ntfs_udl.h tanalyse.c tanalyse.h tdelete.c tdelete.h tdisksel.c tdisksel.h tdiskop.c tdiskop.h thfs.c thfs.h tload.c tload.h tlog.c tlog.h tmbrcode.c tmbrcode.h tntfs.c tntfs.h toptions.c toptions.h tpartwr.c tpartwr.h
-photorec_SOURCES = photorec.c photorec.h phcfg.c phcfg.h phrecn.c phrecn.h dir.c dir.h ext2grp.c ext2grp.h ext2p.c ext2p.h ext2_dir.c ext2_dir.h ext2_inc.h fat_dir.c fat_dir.h fatp.c fatp.h filegen.c filegen.h file_7z.c file_a.c file_ab.c file_abcdp.c file_ace.c file_ahn.c file_aif.c file_all.c file_als.c file_amd.c file_amr.c file_arj.c file_asf.c file_asm.c file_atd.c file_au.c file_bkf.c file_bld.c file_bmp.c file_bz2.c file_cab.c file_cam.c file_chm.c file_cm.c file_compress.c file_crw.c file_ctg.c file_cwk.c file_dat.c file_dbf.c file_dim.c file_dir.c file_djv.c file_doc.c file_dpx.c file_drw.c file_ds2.c file_dsc.c file_dss.c file_dta.c file_dump.c file_dv.c file_dwg.c file_elf.c file_emf.c file_evt.c file_exe.c pe.h file_ext.c file_fcp.c file_fcs.c file_fbk.c file_fdb.c file_fh10.c file_fh5.c file_fits.c file_flac.c file_flv.c file_fob.c file_frm.c file_fs.c file_gho.c file_gif.c file_gpg.c file_gz.c file_ifo.c file_imb.c file_indd.c file_iso.c file_itu.c file_jpg.c file_jpg.h file_kdb.c file_lnk.c file_logic.c file_m2ts.c file_max.c file_mb.c file_mcd.c file_mdb.c file_mdf.c file_mfg.c file_mid.c file_mkv.c file_mov.c file_mp3.c file_mpg.c file_mrw.c file_mus.c file_mysql.c file_njx.c file_ogg.c file_one.c file_orf.c file_paf.c file_pap.c file_pcap.c file_pct.c file_pcx.c file_pdf.c file_pfx.c file_png.c file_prc.c file_prt.c file_ps.c file_psd.c file_psp.c file_pst.c file_ptb.c file_qbb.c file_qdf.c file_qxd.c file_ra.c file_raf.c file_rar.c file_raw.c file_rdc.c file_reg.c file_res.c file_riff.c file_rm.c file_rns.c file_rpm.c file_sib.c file_sit.c file_skp.c file_sp3.c file_sp3.h file_spe.c file_spf.c file_spss.c file_sql.c file_sqm.c file_stl.c file_stu.c file_swf.c file_tar.c file_tar.h file_tax.c file_tib.c file_tiff.c file_tph.c file_txt.c file_veg.c file_vmdk.c file_wks.c file_wmf.c file_wnk.c file_wpd.c file_wv.c file_x3f.c file_xcf.c file_xm.c file_xsv.c file_zip.c memmem.h geometry.c list.c list.h ole.h ntfs_dir.c ntfs_dir.h ntfsp.c ntfsp.h ntfs_inc.h pblocksize.c pblocksize.h pdisksel.c pdisksel.h pfree_whole.c pfree_whole.h ppartsel.c ppartsel.h sessionp.c sessionp.h $(base_C) $(base_H) $(fs_C) $(fs_H) $(ICON_PHOTOREC)
+photorec_SOURCES = photorec.c photorec.h phcfg.c phcfg.h phrecn.c phrecn.h dir.c dir.h ext2grp.c ext2grp.h ext2p.c ext2p.h ext2_dir.c ext2_dir.h ext2_inc.h fat_dir.c fat_dir.h fatp.c fatp.h filegen.c filegen.h file_7z.c file_a.c file_ab.c file_abcdp.c file_ace.c file_ahn.c file_aif.c file_all.c file_als.c file_amd.c file_amr.c file_arj.c file_asf.c file_asm.c file_atd.c file_au.c file_bkf.c file_bld.c file_bmp.c file_bz2.c file_cab.c file_cam.c file_chm.c file_cm.c file_compress.c file_crw.c file_ctg.c file_cwk.c file_dat.c file_dbf.c file_dim.c file_dir.c file_djv.c file_doc.c file_dpx.c file_drw.c file_ds2.c file_dsc.c file_dss.c file_dta.c file_dump.c file_dv.c file_dwg.c file_elf.c file_emf.c file_evt.c file_exe.c pe.h file_ext.c file_fcp.c file_fcs.c file_fbk.c file_fdb.c file_fh10.c file_fh5.c file_fits.c file_flac.c file_flv.c file_fob.c file_frm.c file_fs.c file_gho.c file_gif.c file_gpg.c file_gz.c file_ifo.c file_imb.c file_indd.c file_iso.c file_itu.c file_jpg.c file_jpg.h file_kdb.c file_lnk.c file_logic.c file_m2ts.c file_max.c file_mb.c file_mcd.c file_mdb.c file_mdf.c file_mfg.c file_mid.c file_mkv.c file_mov.c file_mp3.c file_mpg.c file_mrw.c file_mus.c file_mysql.c file_njx.c file_ogg.c file_one.c file_orf.c file_paf.c file_pap.c file_pcap.c file_pct.c file_pcx.c file_pdf.c file_pfx.c file_png.c file_prc.c file_prt.c file_ps.c file_psd.c file_psp.c file_pst.c file_ptb.c file_qbb.c file_qdf.c file_qxd.c file_ra.c file_raf.c file_rar.c file_raw.c file_rdc.c file_reg.c file_res.c file_riff.c file_rm.c file_rns.c file_rpm.c file_sib.c file_sit.c file_skp.c file_sp3.c file_sp3.h file_spe.c file_spf.c file_spss.c file_sql.c file_sqm.c file_stl.c file_stu.c file_swf.c file_tar.c file_tar.h file_tax.c file_tib.c file_tiff.c file_tiff.h file_tph.c file_txt.c file_veg.c file_vmdk.c file_wks.c file_wmf.c file_wnk.c file_wpd.c file_wv.c file_x3f.c file_xcf.c file_xm.c file_xsv.c file_zip.c memmem.h geometry.c list.c list.h ole.h ntfs_dir.c ntfs_dir.h ntfsp.c ntfsp.h ntfs_inc.h pblocksize.c pblocksize.h pdisksel.c pdisksel.h pfree_whole.c pfree_whole.h ppartsel.c ppartsel.h sessionp.c sessionp.h $(base_C) $(base_H) $(fs_C) $(fs_H) $(ICON_PHOTOREC)
#diskcp_SOURCES = diskcp.c types.h
diff --git a/src/file_jpg.c b/src/file_jpg.c
index d57b22a..f11d407 100644
--- a/src/file_jpg.c
+++ b/src/file_jpg.c
@@ -40,6 +40,7 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#include "file_tiff.h"
extern const file_hint_t file_hint_indd;
@@ -61,25 +62,6 @@ static const unsigned char jpg_header_app0[4]= { 0xff,0xd8,0xff,0xe0};
static const unsigned char jpg_header_app1[4]= { 0xff,0xd8,0xff,0xe1};
static const unsigned char jpg_header_com[4]= { 0xff,0xd8,0xff,0xfe};
static const unsigned char jpg_footer[2]= { 0xff,0xd9};
-static const unsigned char tiff_header_be[4]= { 'M','M',0x00, 0x2a};
-static const unsigned char tiff_header_le[4]= { 'I','I',0x2a, 0x00};
-
-struct tiff_entry {
- uint32_t magic;
- uint32_t ifd0_offset;
-} __attribute__ ((__packed__));
-
-struct ifd_entry {
- uint16_t tag;
- uint16_t type;
- uint32_t count;
- uint32_t offset;
-} __attribute__ ((__packed__));
-
-struct ifd_header {
- uint16_t nbr_fields;
- struct ifd_entry ifd;
-} __attribute__ ((__packed__));
static void register_header_check_jpg(file_stat_t *file_stat)
{
@@ -88,114 +70,6 @@ static void register_header_check_jpg(file_stat_t *file_stat)
register_header_check(0, jpg_header_com,sizeof(jpg_header_com), &header_check_jpg, file_stat);
}
-static const char *get_date_from_tiff_header_aux(const struct tiff_entry *tiff, const unsigned int tiff_size, const unsigned int tag)
-{
- if(tiff_size < sizeof(struct tiff_entry))
- return NULL;
- if(memcmp(&tiff->magic, tiff_header_be, sizeof(tiff_header_be))==0)
- {
- if(tiff_size < be32(tiff->ifd0_offset)+sizeof(struct ifd_entry))
- return NULL;
- {
- const struct ifd_header *ifd0=(const struct ifd_header *)((const char*)tiff + be32(tiff->ifd0_offset));
- const struct ifd_header *ifd1=NULL;
- const struct ifd_entry *ifd;
- unsigned int j;
- for(j=0, ifd=&ifd0->ifd;
- (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<be16(ifd0->nbr_fields);
- j++, ifd++)
- {
- if(be16(ifd->tag)==tag)
- {
- if(be32(ifd->offset)+19 < tiff_size)
- return (const char*)tiff+be32(ifd->offset);
- }
- else if(be16(ifd->tag)==0x8769) /* Exif IFD Pointer */
- {
- ifd1=(const struct ifd_header *)((const char*)tiff + be32(ifd->offset));
- }
- }
- if(ifd1!=NULL)
- { /* Exif */
- for(j=0, ifd=&ifd1->ifd;
- (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<be16(ifd1->nbr_fields);
- j++, ifd++)
- {
- if(be16(ifd->tag)==tag)
- {
- if(be32(ifd->offset)+19 < tiff_size)
- return (const char*)tiff+be32(ifd->offset);
- }
- }
- }
- }
- }
- else if(memcmp(&tiff->magic, tiff_header_le, sizeof(tiff_header_le))==0)
- {
- if(tiff_size < le32(tiff->ifd0_offset)+sizeof(struct ifd_entry))
- return NULL;
- {
- const struct ifd_header *ifd0=(const struct ifd_header *)((const char*)tiff + le32(tiff->ifd0_offset));
- const struct ifd_header *ifd1=NULL;
- const struct ifd_entry *ifd;
- unsigned int j;
- for(j=0, ifd=&ifd0->ifd;
- (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<le16(ifd0->nbr_fields);
- j++, ifd++)
- {
- if(le16(ifd->tag)==tag)
- {
- if(le32(ifd->offset)+19 < tiff_size)
- return (const char*)tiff+le32(ifd->offset);
- }
- else if(le16(ifd->tag)==0x8769) /* Exif IFD Pointer */
- {
- ifd1=(const struct ifd_header *)((const char*)tiff + le32(ifd->offset));
- }
- }
- if(ifd1!=NULL)
- { /* Exif */
- for(j=0, ifd=&ifd1->ifd;
- (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<le16(ifd1->nbr_fields);
- j++, ifd++)
- {
- if(le16(ifd->tag)==tag) /* DateTimeOriginal */
- {
- if(le32(ifd->offset)+19 < tiff_size)
- return (const char*)tiff+le32(ifd->offset);
- }
- }
- }
- }
- }
- return NULL;
-}
-
-static time_t get_date_from_tiff_header(const struct tiff_entry *tiff, const unsigned int tiff_size)
-{
- const char *date_asc;
- struct tm tm_time;
- /* DateTimeOriginal */
- date_asc=get_date_from_tiff_header_aux(tiff, tiff_size, 0x9003);
- /* DateTimeDigitalized*/
- if(date_asc==NULL)
- date_asc=get_date_from_tiff_header_aux(tiff, tiff_size, 0x9004);
- if(date_asc==NULL)
- date_asc=get_date_from_tiff_header_aux(tiff, tiff_size, 0x132);
- if(date_asc==NULL)
- return (time_t)0;
- memset(&tm_time, 0, sizeof(tm_time));
- tm_time.tm_sec=(date_asc[17]-'0')*10+(date_asc[18]-'0'); /* seconds 0-59 */
- tm_time.tm_min=(date_asc[14]-'0')*10+(date_asc[15]-'0'); /* minutes 0-59 */
- tm_time.tm_hour=(date_asc[11]-'0')*10+(date_asc[12]-'0'); /* hours 0-23*/
- tm_time.tm_mday=(date_asc[8]-'0')*10+(date_asc[9]-'0'); /* day of the month 1-31 */
- tm_time.tm_mon=(date_asc[5]-'0')*10+(date_asc[6]-'0')-1; /* month 0-11 */
- tm_time.tm_year=(date_asc[0]-'0')*1000+(date_asc[1]-'0')*100+
- (date_asc[2]-'0')*10+(date_asc[3]-'0')-1900; /* year */
- tm_time.tm_isdst = -1; /* unknown daylight saving time */
- return mktime(&tm_time);
-}
-
static int header_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
if(file_recovery!=NULL && file_recovery->file_stat!=NULL &&
diff --git a/src/file_tiff.c b/src/file_tiff.c
index af7063c..56e795e 100644
--- a/src/file_tiff.c
+++ b/src/file_tiff.c
@@ -2,7 +2,7 @@
File: file_tiff.c
- Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+ Copyright (C) 1998-2005,2007-2009 Christophe GRENIER <grenier@cgsecurity.org>
This software is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,17 +26,20 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
#include <stdio.h>
#include "types.h"
#include "filegen.h"
-#include "memmem.h"
+#include "common.h"
+#include "file_tiff.h"
static void register_header_check_tiff(file_stat_t *file_stat);
static int header_check_tiff(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-/*
-static int64_t test_tiff(FILE *infile);
static void file_check_tiff(file_recovery_t *file_recovery);
-*/
+static uint64_t header_check_tiff_be(FILE *in, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
+static uint64_t header_check_tiff_le(FILE *in, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
const file_hint_t file_hint_tiff= {
.extension="tif",
@@ -50,6 +53,115 @@ const file_hint_t file_hint_tiff= {
static const unsigned char tiff_header_be[4]= { 'M','M',0x00, 0x2a};
static const unsigned char tiff_header_le[4]= { 'I','I',0x2a, 0x00};
+#define TIFFTAG_MAKE 271 /* scanner manufacturer name */
+
+static const char *find_tag_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag)
+{
+ if(tiff_size < sizeof(TIFFHeader))
+ return NULL;
+ if(memcmp(&tiff->tiff_magic, tiff_header_be, sizeof(tiff_header_be))==0)
+ {
+ if(tiff_size < be32(tiff->tiff_diroff)+sizeof(TIFFDirEntry))
+ return NULL;
+ {
+ const struct ifd_header *ifd0=(const struct ifd_header *)((const char*)tiff + be32(tiff->tiff_diroff));
+ const struct ifd_header *ifd1=NULL;
+ const TIFFDirEntry *ifd;
+ unsigned int j;
+ for(j=0, ifd=&ifd0->ifd;
+ (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<be16(ifd0->nbr_fields);
+ j++, ifd++)
+ {
+ if(be16(ifd->tdir_tag)==tag)
+ {
+ if(be32(ifd->tdir_offset)+19 < tiff_size)
+ return (const char*)tiff+be32(ifd->tdir_offset);
+ }
+ else if(be16(ifd->tdir_tag)==TIFFTAG_EXIFIFD) /* Exif IFD Pointer */
+ {
+ ifd1=(const struct ifd_header *)((const char*)tiff + be32(ifd->tdir_offset));
+ }
+ }
+ if(ifd1!=NULL)
+ { /* Exif */
+ for(j=0, ifd=&ifd1->ifd;
+ (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<be16(ifd1->nbr_fields);
+ j++, ifd++)
+ {
+ if(be16(ifd->tdir_tag)==tag)
+ {
+ if(be32(ifd->tdir_offset)+19 < tiff_size)
+ return (const char*)tiff+be32(ifd->tdir_offset);
+ }
+ }
+ }
+ }
+ }
+ else if(memcmp(&tiff->tiff_magic, tiff_header_le, sizeof(tiff_header_le))==0)
+ {
+ if(tiff_size < le32(tiff->tiff_diroff)+sizeof(TIFFDirEntry))
+ return NULL;
+ {
+ const struct ifd_header *ifd0=(const struct ifd_header *)((const char*)tiff + le32(tiff->tiff_diroff));
+ const struct ifd_header *ifd1=NULL;
+ const TIFFDirEntry *ifd;
+ unsigned int j;
+ for(j=0, ifd=&ifd0->ifd;
+ (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<le16(ifd0->nbr_fields);
+ j++, ifd++)
+ {
+ if(le16(ifd->tdir_tag)==tag)
+ {
+ if(le32(ifd->tdir_offset)+19 < tiff_size)
+ return (const char*)tiff+le32(ifd->tdir_offset);
+ }
+ else if(le16(ifd->tdir_tag)==TIFFTAG_EXIFIFD) /* Exif IFD Pointer */
+ {
+ ifd1=(const struct ifd_header *)((const char*)tiff + le32(ifd->tdir_offset));
+ }
+ }
+ if(ifd1!=NULL)
+ { /* Exif */
+ for(j=0, ifd=&ifd1->ifd;
+ (const char*)(ifd+1) <= (const char*)tiff+tiff_size && j<le16(ifd1->nbr_fields);
+ j++, ifd++)
+ {
+ if(le16(ifd->tdir_tag)==tag) /* DateTimeOriginal */
+ {
+ if(le32(ifd->tdir_offset)+19 < tiff_size)
+ return (const char*)tiff+le32(ifd->tdir_offset);
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+time_t get_date_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size)
+{
+ const char *date_asc;
+ struct tm tm_time;
+ /* DateTimeOriginal */
+ date_asc=find_tag_from_tiff_header(tiff, tiff_size, 0x9003);
+ /* DateTimeDigitalized*/
+ if(date_asc==NULL)
+ date_asc=find_tag_from_tiff_header(tiff, tiff_size, 0x9004);
+ if(date_asc==NULL)
+ date_asc=find_tag_from_tiff_header(tiff, tiff_size, 0x132);
+ if(date_asc==NULL)
+ return (time_t)0;
+ memset(&tm_time, 0, sizeof(tm_time));
+ tm_time.tm_sec=(date_asc[17]-'0')*10+(date_asc[18]-'0'); /* seconds 0-59 */
+ tm_time.tm_min=(date_asc[14]-'0')*10+(date_asc[15]-'0'); /* minutes 0-59 */
+ tm_time.tm_hour=(date_asc[11]-'0')*10+(date_asc[12]-'0'); /* hours 0-23*/
+ tm_time.tm_mday=(date_asc[8]-'0')*10+(date_asc[9]-'0'); /* day of the month 1-31 */
+ tm_time.tm_mon=(date_asc[5]-'0')*10+(date_asc[6]-'0')-1; /* month 0-11 */
+ tm_time.tm_year=(date_asc[0]-'0')*1000+(date_asc[1]-'0')*100+
+ (date_asc[2]-'0')*10+(date_asc[3]-'0')-1900; /* year */
+ tm_time.tm_isdst = -1; /* unknown daylight saving time */
+ return mktime(&tm_time);
+}
static void register_header_check_tiff(file_stat_t *file_stat)
{
@@ -59,45 +171,359 @@ static void register_header_check_tiff(file_stat_t *file_stat)
static int header_check_tiff(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- const unsigned char pentax_sig[7]= { 'P', 'E', 'N', 'T', 'A', 'X', ' '};
- const unsigned char nikon_sig[17]= { 'N', 'I', 'K', 'O', 'N', ' ', 'C', 'O', 'R', 'P', 'O', 'R', 'A', 'T', 'I', 'O', 'N'};
- const unsigned char dcr_sig[5]= { '.', 'D', 'C', 'R', 0x00};
- const unsigned char sony_sig[5]= { 'S', 'O', 'N', 'Y', 0x00};
- const unsigned char sony_sig_arw[6]= { 'S', 'O', 'N', 'Y', ' ', 0x00};
if(memcmp(buffer,tiff_header_be,sizeof(tiff_header_be))==0 ||
memcmp(buffer,tiff_header_le,sizeof(tiff_header_le))==0)
{
reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_tiff.extension;
/* Canon RAW */
if(buffer[8]=='C' && buffer[9]=='R' && buffer[10]==2)
file_recovery_new->extension="cr2";
- /* Pentax RAW */
- else if(td_memmem(buffer, buffer_size, pentax_sig, sizeof(pentax_sig))!=NULL)
- file_recovery_new->extension="pef";
- /* Nikon RAW */
- else if(td_memmem(buffer, buffer_size, nikon_sig, sizeof(nikon_sig))!=NULL)
- file_recovery_new->extension="nef";
- /* Kodak RAW */
- else if(td_memmem(buffer, buffer_size, dcr_sig, sizeof(dcr_sig))!=NULL)
- file_recovery_new->extension="dcr";
- /* Sony RAW */
- else if(td_memmem(buffer, buffer_size, sony_sig, sizeof(sony_sig))!=NULL)
- file_recovery_new->extension="sr2";
- else if(td_memmem(buffer, buffer_size, sony_sig_arw, sizeof(sony_sig_arw))!=NULL)
- file_recovery_new->extension="arw";
else
- file_recovery_new->extension=file_hint_tiff.extension;
+ {
+ const char *tag_make;
+ tag_make=find_tag_from_tiff_header((const TIFFHeader *)buffer, buffer_size, TIFFTAG_MAKE);
+ if(tag_make!=NULL)
+ {
+ if(strcmp(tag_make, "PENTAX Corporation ")==0)
+ file_recovery_new->extension="pef";
+ else if(strcmp(tag_make, "NIKON CORPORATION")==0)
+ file_recovery_new->extension="nef";
+ else if(strcmp(tag_make, "Kodak")==0)
+ file_recovery_new->extension="dcr";
+ else if(strcmp(tag_make, "Sony")==0)
+ file_recovery_new->extension="sr2";
+ else if(strcmp(tag_make, "Sony ")==0)
+ file_recovery_new->extension="arw";
+ }
+ }
+ file_recovery_new->time=get_date_from_tiff_header((const TIFFHeader *)buffer, buffer_size);
+ file_recovery_new->file_check=&file_check_tiff;
return 1;
}
return 0;
}
-/*
-// Seems to be wrong
-static void file_check_tiff(file_recovery_t *file_recovery)
+static unsigned int type2size(const unsigned int type)
{
- const unsigned char tiff_footer[2]= {0xff, 0xd9};
- file_search_footer(file_recovery, tiff_footer,sizeof(tiff_footer));
+ switch(type)
+ {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ return 1;
+ case 3:
+ case 8:
+ return 2;
+ case 4:
+ case 9:
+ case 11:
+ return 4;
+ case 5:
+ case 10:
+ case 12:
+ return 8;
+ default:
+ return 1;
+ }
+}
+#ifdef DEBUG_TIFF
+static const char *tag_name(unsigned int tag)
+{
+ switch(tag)
+ {
+ case TIFFTAG_IMAGEDESCRIPTION:
+ return "IMAGEDESCRIPTION";
+ case TIFFTAG_MAKE:
+ return "MAKE";
+ case TIFFTAG_MODEL:
+ return "TIFFTAG_MODEL";
+ case TIFFTAG_SUBIFD:
+ return "SUBIFD";
+ case TIFFTAG_EXIFIFD:
+ return "EXIFIFD";
+ case TIFFTAG_STRIPOFFSETS:
+ return "STRIPOFFSETS";
+ case TIFFTAG_STRIPBYTECOUNTS:
+ return "STRIPBYTECOUNTS";
+ case TIFFTAG_KODAKIFD:
+ return "KODAKIFD";
+ case TIFFTAG_JPEGIFOFFSET:
+ return "JPEGIFOFFSET";
+ case TIFFTAG_JPEGIFBYTECOUNT:
+ return "JPEGIFBYTECOUNT";
+ case TIFFTAG_DNGPRIVATEDATA:
+ return "DNGPRIVATEDATA";
+ case EXIFTAG_MAKERNOTE:
+ return "EXIFTAG_MAKERNOTE";
+ default:
+ return "";
+ }
+}
+#endif
+
+static uint64_t header_check_tiff_le(FILE *in, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+{
+ unsigned char buffer[8192];
+ unsigned int i,n;
+ int data_read;
+ uint32_t *tiff_next_diroff;
+ uint64_t max_offset=0;
+ uint64_t strip_offsets=0;
+ uint64_t strip_bytecounts=0;
+ uint64_t jpegifoffset=0;
+ uint64_t jpegifbytecount=0;
+ TIFFDirEntry *entry=(TIFFDirEntry *)&buffer[2];
+ if(depth>4)
+ return 0;
+ if(count>16)
+ return 0;
+ if(tiff_diroff == 0)
+ return 0;
+ if(tiff_diroff % 2 != 0)
+ return -1;
+ if(fseek(in, tiff_diroff, SEEK_SET) < 0)
+ return -1;
+ data_read=fread(buffer, 1, sizeof(buffer), in);
+ if(data_read<2)
+ return -1;
+ n=buffer[0]+(buffer[1]<<8);
+#ifdef DEBUG_TIFF
+ log_info("header_check_tiff_le(in, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+#endif
+ //sizeof(TIFFDirEntry)=12;
+ if(n > (data_read-2)/12)
+ n=(data_read-2)/12;
+ if(n==0)
+ return 0;
+ for(i=0;i<n;i++)
+ {
+ uint64_t val=(uint64_t)le32(entry->tdir_count)*type2size(le16(entry->tdir_type));
+#ifdef DEBUG_TIFF
+ log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx)\n",
+ i,
+ le16(entry->tdir_tag),
+ le16(entry->tdir_tag),
+ tag_name(le16(entry->tdir_tag)),
+ le16(entry->tdir_type),
+ (long unsigned)le32(entry->tdir_count),
+ (long unsigned)le32(entry->tdir_offset),
+ (long unsigned)le32(entry->tdir_offset));
+#endif
+ if(val>4)
+ {
+ const uint64_t new_offset=le32(entry->tdir_offset)+val;
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ switch(le16(entry->tdir_tag))
+ {
+ case TIFFTAG_JPEGIFOFFSET:
+ jpegifoffset=le32(entry->tdir_offset);
+ break;
+ case TIFFTAG_JPEGIFBYTECOUNT:
+ jpegifbytecount=le32(entry->tdir_offset);
+ break;
+ case TIFFTAG_STRIPOFFSETS:
+ strip_offsets=le32(entry->tdir_offset);
+ break;
+ case TIFFTAG_STRIPBYTECOUNTS:
+ strip_bytecounts=le32(entry->tdir_offset);
+ break;
+ case TIFFTAG_EXIFIFD:
+ case TIFFTAG_KODAKIFD:
+ case TIFFTAG_SUBIFD:
+ if(val==4)
+ {
+ uint64_t new_offset=header_check_tiff_le(in, le32(entry->tdir_offset), depth+1, 0);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ else if(val>4)
+ {
+ const unsigned int nbr=le32(entry->tdir_count);
+ if(nbr<25)
+ {
+ unsigned int j;
+ uint32_t *subifd_offsetp;
+ subifd_offsetp=(uint32_t *)malloc(nbr*sizeof(*subifd_offsetp));
+ if(fseek(in, le32(entry->tdir_offset), SEEK_SET) < 0)
+ return -1;
+ if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, in) != nbr)
+ return -1;
+ for(j=0; j<nbr; j++)
+ {
+ const uint64_t new_offset=header_check_tiff_le(in, le32(subifd_offsetp[j]), depth+1, 0);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset = new_offset;
+ }
+ }
+ }
+ break;
+ }
+ entry++;
+ }
+ if(strip_bytecounts > 0 && max_offset < strip_offsets + strip_bytecounts)
+ max_offset = strip_offsets + strip_bytecounts;
+ if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount)
+ max_offset = jpegifoffset + jpegifbytecount;
+ tiff_next_diroff=(uint32_t *)entry;
+ {
+ uint64_t new_offset=header_check_tiff_le(in, le32(*tiff_next_diroff), depth, count+1);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ return max_offset;
+}
+
+static uint64_t header_check_tiff_be(FILE *in, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+{
+ unsigned char buffer[8192];
+ unsigned int i,n;
+ int data_read;
+ uint32_t *tiff_next_diroff;
+ uint64_t max_offset=0;
+ uint64_t strip_offsets=0;
+ uint64_t strip_bytecounts=0;
+ uint64_t jpegifoffset=0;
+ uint64_t jpegifbytecount=0;
+ TIFFDirEntry *entry=(TIFFDirEntry *)&buffer[2];
+ if(depth>4)
+ return 0;
+ if(count>16)
+ return 0;
+ if(tiff_diroff == 0)
+ return 0;
+ if(tiff_diroff % 2 != 0)
+ return -1;
+ if(fseek(in, tiff_diroff, SEEK_SET) < 0)
+ return -1;
+ data_read=fread(buffer, 1, sizeof(buffer), in);
+ if(data_read<2)
+ return -1;
+ n=(buffer[0]<<8)+buffer[1];
+#ifdef DEBUG_TIFF
+ log_info("header_check_tiff_be(in, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+#endif
+ //sizeof(TIFFDirEntry)=12;
+ if(n > (data_read-2)/12)
+ n=(data_read-2)/12;
+ if(n==0)
+ return 0;
+ for(i=0;i<n;i++)
+ {
+ const uint64_t val=(uint64_t)be32(entry->tdir_count)*type2size(be16(entry->tdir_type));
+#ifdef DEBUG_TIFF
+ log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx)\n",
+ i,
+ be16(entry->tdir_tag),
+ be16(entry->tdir_tag),
+ tag_name(be16(entry->tdir_tag)),
+ be16(entry->tdir_type),
+ (long unsigned)be32(entry->tdir_count),
+ (long unsigned)be32(entry->tdir_offset),
+ (long unsigned)be32(entry->tdir_offset));
+#endif
+ if(val>4)
+ {
+ const uint64_t new_offset=be32(entry->tdir_offset)+val;
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ switch(be16(entry->tdir_tag))
+ {
+ case TIFFTAG_JPEGIFOFFSET:
+ jpegifoffset=be32(entry->tdir_offset);
+ break;
+ case TIFFTAG_JPEGIFBYTECOUNT:
+ jpegifbytecount=be32(entry->tdir_offset);
+ break;
+ case TIFFTAG_STRIPOFFSETS:
+ strip_offsets=be32(entry->tdir_offset);
+ break;
+ case TIFFTAG_STRIPBYTECOUNTS:
+ strip_bytecounts=be32(entry->tdir_offset);
+ break;
+ case TIFFTAG_EXIFIFD:
+ case TIFFTAG_KODAKIFD:
+ case TIFFTAG_SUBIFD:
+ if(val==4)
+ {
+ uint64_t new_offset=header_check_tiff_be(in, be32(entry->tdir_offset), depth+1, 0);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ else if(val>4)
+ {
+ const unsigned int nbr=be32(entry->tdir_count);
+ if(nbr<25)
+ {
+ unsigned int j;
+ uint32_t *subifd_offsetp;
+ subifd_offsetp=(uint32_t *)malloc(nbr*sizeof(*subifd_offsetp));
+ if(fseek(in, be32(entry->tdir_offset), SEEK_SET) < 0)
+ return -1;
+ if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, in) != nbr)
+ return -1;
+ for(j=0; j<nbr; j++)
+ {
+ const uint64_t new_offset=header_check_tiff_be(in, be32(subifd_offsetp[j]), depth+1, 0);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset = new_offset;
+ }
+ }
+ }
+ break;
+ }
+ entry++;
+ }
+ if(strip_bytecounts > 0 && max_offset < strip_offsets + strip_bytecounts)
+ max_offset = strip_offsets + strip_bytecounts;
+ if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount)
+ max_offset = jpegifoffset + jpegifbytecount;
+ tiff_next_diroff=(uint32_t *)entry;
+ {
+ uint64_t new_offset=header_check_tiff_be(in, be32(*tiff_next_diroff), depth, count+1);
+ if(new_offset==-1)
+ return -1;
+ if(max_offset < new_offset)
+ max_offset=new_offset;
+ }
+ return max_offset;
+}
+
+static void file_check_tiff(file_recovery_t *fr)
+{
+ static uint64_t calculated_file_size=0;
+ TIFFHeader header;
+ calculated_file_size = 0;
+ fseek(fr->handle, 0, SEEK_SET);
+ if(fread(&header, sizeof(header), 1, fr->handle) != 1)
+ return;
+ if(header.tiff_magic==TIFF_LITTLEENDIAN)
+ calculated_file_size=header_check_tiff_le(fr->handle, le32(header.tiff_diroff), 0, 0);
+ else if(header.tiff_magic==TIFF_BIGENDIAN)
+ calculated_file_size=header_check_tiff_be(fr->handle, be32(header.tiff_diroff), 0, 0);
+ if(fr->file_size < calculated_file_size)
+ fr->file_size=0;
+ /* PhotoRec isn't yet capable to find the correct Sony arw filesize,
+ * so don't truncate them */
+ else if(strcmp(fr->extension,"arw")!=0)
+ fr->file_size=calculated_file_size;
}
-*/
diff --git a/src/file_tiff.h b/src/file_tiff.h
new file mode 100644
index 0000000..0d08970
--- /dev/null
+++ b/src/file_tiff.h
@@ -0,0 +1,56 @@
+/*
+
+ File: file_tiff.h
+
+ Copyright (C) 2009 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#define TIFF_BIGENDIAN 0x4d4d
+#define TIFF_LITTLEENDIAN 0x4949
+#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */
+#define TIFFTAG_MAKE 271 /* scanner manufacturer name */
+#define TIFFTAG_MODEL 272 /* scanner model name/number */
+#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */
+#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */
+#define TIFFTAG_SUBIFD 330
+#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */
+#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */
+#define TIFFTAG_KODAKIFD 33424
+#define TIFFTAG_EXIFIFD 34665
+#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */
+#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */
+
+typedef struct {
+ uint16_t tiff_magic; /* magic number (defines byte order) */
+ uint16_t tiff_version; /* TIFF version number */
+ uint32_t tiff_diroff; /* byte offset to first directory */
+} TIFFHeader;
+
+typedef struct {
+ uint16_t tdir_tag; /* see below */
+ uint16_t tdir_type; /* data type; see below */
+ uint32_t tdir_count; /* number of items; length in spec */
+ uint32_t tdir_offset; /* byte offset to field data */
+} TIFFDirEntry;
+
+struct ifd_header {
+ uint16_t nbr_fields;
+ TIFFDirEntry ifd;
+} __attribute__ ((__packed__));
+
+time_t get_date_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size);
+