void file_check_tiff(file_recovery_t *fr) { static uint64_t calculated_file_size=0; unsigned char *buffer=(unsigned char *)MALLOC(8192); const TIFFHeader *header=(const TIFFHeader *)buffer; int data_read; calculated_file_size = 0; if(fseek(fr->handle, 0, SEEK_SET) < 0 || (data_read=fread(buffer, 1, 8192, fr->handle)) < (int)sizeof(TIFFHeader)) { free(buffer); fr->file_size=0; return; } if(header->tiff_magic==TIFF_LITTLEENDIAN) calculated_file_size=header_check_tiff_le(fr, le32(header->tiff_diroff), 0, 0); else if(header->tiff_magic==TIFF_BIGENDIAN) calculated_file_size=header_check_tiff_be(fr, be32(header->tiff_diroff), 0, 0); #ifdef DEBUG_TIFF log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size); log_info("TIFF Estimated %llu\n", (unsigned long long)calculated_file_size); #endif if(fr->file_size < calculated_file_size || calculated_file_size==0) fr->file_size=0; /* PhotoRec isn't yet capable to find the correct filesize for * Sony arw and dng, * Panasonic raw/rw2, * Minolta tif * Sony sr2 * so don't truncate them */ else if(strcmp(fr->extension,"cr2")==0 || strcmp(fr->extension,"dcr")==0 || strcmp(fr->extension,"nef")==0 || strcmp(fr->extension,"orf")==0 || strcmp(fr->extension,"pef")==0 || (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) || strcmp(fr->extension,"wdp")==0) fr->file_size=calculated_file_size; free(buffer); }
uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count) { unsigned char buffer[8192]; unsigned int i,n; int data_read; const uint32_t *tiff_next_diroff; uint64_t max_offset=0; uint64_t alphaoffset=0; uint64_t alphabytecount=0; uint64_t imageoffset=0; uint64_t imagebytecount=0; uint64_t jpegifoffset=0; uint64_t jpegifbytecount=0; uint64_t strip_offsets=0; uint64_t strip_bytecounts=0; uint64_t tile_offsets=0; uint64_t tile_bytecounts=0; unsigned int tdir_tag_old=0; unsigned int sorted_tag_error=0; const TIFFDirEntry *entry=(const TIFFDirEntry *)&buffer[2]; const TIFFDirEntry *entry_strip_offsets=NULL; const TIFFDirEntry *entry_strip_bytecounts=NULL; const TIFFDirEntry *entry_tile_offsets=NULL; const TIFFDirEntry *entry_tile_bytecounts=NULL; #ifdef DEBUG_TIFF log_info("header_check_tiff_le(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count); #endif if(depth>4) return -1; if(count>16) return -1; if(tiff_diroff < sizeof(TIFFHeader)) return -1; if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0) return -1; data_read=fread(buffer, 1, sizeof(buffer), fr->handle); if(data_read<2) return -1; n=buffer[0]+(buffer[1]<<8); #ifdef DEBUG_TIFF log_info("header_check_tiff_le(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n); #endif //sizeof(TIFFDirEntry)=12; if(n > (unsigned)(data_read-2)/12) n=(data_read-2)/12; if(n==0) return -1; for(i=0;i<n;i++) { const unsigned int tdir_tag=le16(entry->tdir_tag); const uint64_t val=(uint64_t)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type)); #ifdef DEBUG_TIFF log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx) val=%lu\n", i, tdir_tag, tdir_tag, tag_name(tdir_tag), le16(entry->tdir_type), (long unsigned)le32(entry->tdir_count), (long unsigned)le32(entry->tdir_offset), (long unsigned)le32(entry->tdir_offset), (long unsigned)val); #endif if(tdir_tag_old > tdir_tag) { /* Entries must be sorted by tag, some SR2 file doesn't respected this rule */ sorted_tag_error++; if(sorted_tag_error > 1 && strcmp(fr->extension,"sr2")!=0) return -1; } if(val>4) { const uint64_t new_offset=le32(entry->tdir_offset)+val; if(new_offset==0) return -1; if(max_offset < new_offset) max_offset=new_offset; } if(le32(entry->tdir_count)==1 && val<=4) { const unsigned int tmp=tiff_le_read(&entry->tdir_offset, le16(entry->tdir_type)); switch(tdir_tag) { case TIFFTAG_ALPHABYTECOUNT: alphabytecount=tmp; break; case TIFFTAG_ALPHAOFFSET: alphaoffset=tmp; break; case TIFFTAG_IMAGEBYTECOUNT: imagebytecount=tmp; break; case TIFFTAG_IMAGEOFFSET: imageoffset=tmp; break; case TIFFTAG_JPEGIFBYTECOUNT: jpegifbytecount=tmp; break; case TIFFTAG_JPEGIFOFFSET: jpegifoffset=tmp; break; case TIFFTAG_STRIPBYTECOUNTS: strip_bytecounts=tmp; break; case TIFFTAG_STRIPOFFSETS: strip_offsets=tmp; break; case TIFFTAG_TILEBYTECOUNTS: tile_bytecounts=tmp; break; case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break; case TIFFTAG_EXIFIFD: case TIFFTAG_KODAKIFD: { const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0); if(new_offset==-1) return -1; if(max_offset < new_offset) max_offset=new_offset; } break; case TIFFTAG_SUBIFD: if(fr->extension!=NULL && strcmp(fr->extension, "arw")==0) { /* DSLR-A100 is boggus, may be A100DataOffset */ if(max_offset < tmp) max_offset=tmp; } else { const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0); if(new_offset==-1) return -1; if(max_offset < new_offset) max_offset=new_offset; } break; #ifdef ENABLE_TIFF_MAKERNOTE case EXIFTAG_MAKERNOTE: { const uint64_t new_offset=tiff_le_makernote(fr->handle, tmp); if(new_offset==-1) return -1; if(max_offset < new_offset) max_offset=new_offset; } break; #endif } } else if(le32(entry->tdir_count) > 1) { switch(tdir_tag) { case TIFFTAG_EXIFIFD: case TIFFTAG_KODAKIFD: case TIFFTAG_SUBIFD: if(le16(entry->tdir_type)==4) { const unsigned int nbr=(le32(entry->tdir_count)<32?le32(entry->tdir_count):32); unsigned int j; uint32_t *subifd_offsetp; if(fseek(fr->handle, le32(entry->tdir_offset), SEEK_SET) < 0) { return -1; } subifd_offsetp=(uint32_t *)MALLOC(nbr*sizeof(*subifd_offsetp)); if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, fr->handle) != nbr) { free(subifd_offsetp); return -1; } for(j=0; j<nbr; j++) { const uint64_t new_offset=header_check_tiff_le(fr, le32(subifd_offsetp[j]), depth+1, 0); if(new_offset==-1) { free(subifd_offsetp); return -1; } if(max_offset < new_offset) max_offset = new_offset; } free(subifd_offsetp); } break; case TIFFTAG_STRIPOFFSETS: entry_strip_offsets=entry; break; case TIFFTAG_STRIPBYTECOUNTS: entry_strip_bytecounts=entry; break; case TIFFTAG_TILEBYTECOUNTS: entry_tile_bytecounts=entry; break; case TIFFTAG_TILEOFFSETS: entry_tile_offsets=entry; break; } } tdir_tag_old=tdir_tag; entry++; } if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount) max_offset = alphaoffset + alphabytecount; if(imagebytecount > 0 && max_offset < imageoffset + imagebytecount) max_offset = imageoffset + imagebytecount; if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount) max_offset = jpegifoffset + jpegifbytecount; if(strip_bytecounts > 0 && strip_offsets!=0xffffffff && max_offset < strip_offsets + strip_bytecounts) max_offset = strip_offsets + strip_bytecounts; if(tile_bytecounts > 0 && tile_offsets!=0xffffffff && max_offset < tile_offsets + tile_bytecounts) max_offset = tile_offsets + tile_bytecounts; if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL) { const uint64_t tmp=parse_strip_le(fr->handle, entry_strip_offsets, entry_strip_bytecounts); if(tmp==-1) return -1; if(max_offset < tmp) max_offset=tmp; } if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL) { const uint64_t tmp=parse_strip_le(fr->handle, entry_tile_offsets, entry_tile_bytecounts); if(tmp==-1) return -1; if(max_offset < tmp) max_offset=tmp; } tiff_next_diroff=(const uint32_t *)entry; if(le32(*tiff_next_diroff) > 0) { const uint64_t new_offset=header_check_tiff_le(fr, le32(*tiff_next_diroff), depth+1, count+1); if(new_offset != -1 && max_offset < new_offset) max_offset=new_offset; } return max_offset; }