示例#1
0
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);
}
示例#2
0
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;
}