/* scans first IDF and returns the type of the n-th tag */ uint32 TIFFGetRawTagTypeListEntry( TIFF * tif, int tagidx ) { if (tagidx >= 0) { ifd_entry_t ifd_entry; ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx ); return ifd_entry.datatype; } else { /* tag not defined */ fprintf(stderr, "tagidx should be greater 0"); exit(EXIT_FAILURE); } }
/* TODO */ ifd_entry_t TIFFGetRawIFDEntry( TIFF * tif, tag_t tag) { int tagidx = -1; int i; for (i= 0; i < TIFFGetRawTagListCount( tif ); i++) { if (tag == TIFFGetRawTagListEntry( tif, i ) && tag > 253) { tagidx= i; break; }; }; if (tagidx >= 0) { ifd_entry_t ifd_entry; ifd_entry = TIFFGetRawTagIFDListEntry( tif, tagidx ); return ifd_entry; } else { /* tag not defined */ fprintf(stderr, "tag %u (%s) should exist, because defined\n", tag, TIFFTagName(tif, tag)); exit(EXIT_FAILURE); } }
/* check if offsets are greater zero */ ret_t check_all_offsets_are_greater_zero(ctiff_t * ctif) { GET_EMPTY_RET(ret) tifp_check( ctif); int count = get_ifd0_count( ctif); int tagidx; for (tagidx = 0; tagidx< count; tagidx++) { ifd_entry_t ifd_entry = TIFFGetRawTagIFDListEntry( ctif, tagidx ); uint32 tag = TIFFGetRawTagListEntry( ctif, tagidx); if (ifd_entry.value_or_offset==is_offset || tag == TIFFTAG_EXIFIFD) { uint32 offset=0; if (ifd_entry.value_or_offset==is_offset) offset = ifd_entry.data32offset; else if (tag == TIFFTAG_EXIFIFD) { if (ifd_entry.count > 1) { ret = set_value_found_ret(&ret, int2str(ifd_entry.count)); ret.returncode = tagerror_expected_count_isgreaterone; return ret; } switch (ifd_entry.datatype) { case TIFF_LONG: { /* correct type */ offset = ifd_entry.data32; break; } default: { /* incorrect type for EXIF IFD */ ret = set_value_found_ret(&ret, TIFFTypeName(ifd_entry.datatype)); ret.returncode = tagerror_unexpected_type_found; return ret; /* break; */ }; } } /* end else if tag == TIFFTAG_EXIFIFD */ if ( 0 == offset) { // FIXME: tif_fails? char array[TIFFAILSTRLEN]; snprintf(array, sizeof(array), "tag %u pointing to 0x%08x", tag, offset); ret = set_value_found_ret (&ret, array); ret.returncode = tagerror_offset_is_zero; return ret; } } } ret.returncode=is_valid; return ret; }
/* check if offsets are word aligned */ ret_t check_all_offsets_are_word_aligned(ctiff_t * ctif) { //printf("check if all offsets are word aligned\n"); tif_rules("all offsets are word aligned"); int count = get_ifd0_count( ctif); int tagidx; for (tagidx = 0; tagidx< count; tagidx++) { ifd_entry_t ifd_entry = TIFFGetRawTagIFDListEntry( ctif, tagidx ); if (ifd_entry.value_or_offset==is_offset) { uint32 offset = ifd_entry.data32offset; if ( 0 != (offset & 1)) { uint32 tag = TIFFGetRawTagListEntry( ctif, tagidx); // FIXME: tif_fails? char array[TIFFAILSTRLEN]; snprintf(array, sizeof(array), "pointing to 0x%08x and is not word-aligned", offset); return tif_fails_tag( tag, "word-aligned", array); } } } ret_t res; res.returnmsg=NULL; res.returncode=0; return res; }
/* TODO: add support for StripOffsets and StripByteCounts */ mem_map_t * scan_mem_map(ctiff_t * ctif) { assert( NULL != ctif); static mem_map_t memmap; memmap.count = 0; memmap.base_p = NULL; memmap.max_entries = 2048; memmap.base_p = malloc (sizeof(mem_map_entry_t) * memmap.max_entries); if (NULL == memmap.base_p) { perror ("could not allocate mem for memmap, abort"); } /* size of tiff file in bytes */ memmap.max_len = ctif->streamlen; /* header */ add_mem_entry( &memmap, 0, 4, mt_constant); /* IFD0 Offset */ add_mem_entry( &memmap, 4, 4, mt_offset_to_ifd0); /* IFDO */ uint32 ifd = get_ifd0_pos( ctif ); uint16 count = get_ifd0_count( ctif); add_mem_entry( &memmap, ifd, 2, mt_ifd); /* count of tags in ifd */ int ifdbase=2+ifd; /* iterate through IFD0 entries */ uint16 tagidx; ifd_entry_t stripoffset_entry; for (tagidx = 0; tagidx< count; tagidx++) { add_mem_entry( &memmap, ifdbase+(tagidx*12), 8, mt_ifd); /* tagid, field type, count */ ifd_entry_t ifd_entry = TIFFGetRawTagIFDListEntry( ctif, tagidx ); uint32 tag = TIFFGetRawTagListEntry( ctif, tagidx); TIFFDataType datatype = TIFFGetRawTagType( ctif, tag); int datasize; switch (datatype) { case TIFF_ASCII: datasize = 1; break; case TIFF_LONG: datasize = 4; break; case TIFF_SHORT: datasize = 2; break; case TIFF_BYTE: datasize = 1; break; case TIFF_UNDEFINED: datasize = 1; break; case TIFF_RATIONAL: datasize = 8; break; case TIFF_SSHORT: datasize = 2; break; case TIFF_SBYTE: datasize = 1; break; case TIFF_SLONG: datasize = 4; break; case TIFF_SRATIONAL: datasize = 8; break; case TIFF_FLOAT: datasize = 4; break; case TIFF_DOUBLE: datasize = 8; break; default: fprintf(stderr, "unknown datatype %i, possible a program error", datatype); exit(EXIT_FAILURE); } uint32 offset = ifd_entry.data32offset; uint16 count = ifd_entry.count; if (tag == TIFFTAG_STRIPOFFSETS) { if (ifd_entry.value_or_offset == is_offset) { add_mem_entry( &memmap, ifdbase+(tagidx*12)+8,4,mt_ifd_offset_to_standardized_value ); add_mem_entry( &memmap, offset, ((uint32) count)*datasize, mt_ifd_offset_to_stripoffsets ); } else if (ifd_entry.value_or_offset==is_value) { add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_embedded_standardized_value ); } stripoffset_entry=ifd_entry; } else if (ifd_entry.value_or_offset==is_offset) { /* offset */ if (tag < 32768) { /* standard tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_offset_to_standardized_value ); add_mem_entry( &memmap, offset, ((uint32) count)*datasize, mt_standardized_value ); } else if (tag < 65000) { /* registered tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_offset_to_registered_value ); add_mem_entry( &memmap, offset, ((uint32) count)*datasize, mt_registered_value ); } else { /* private tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_offset_to_private_value ); add_mem_entry( &memmap, offset, ((uint32) count)*datasize, mt_private_value ); } } else if (ifd_entry.value_or_offset==is_value) { /* embedded value */ if (tag < 32768) { /* standard tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_embedded_standardized_value ); } else if (tag < 65000) { /* registered tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_embedded_registered_value ); } else { /* private tag */ add_mem_entry( &memmap, ifdbase+(tagidx*12)+8, 4,mt_ifd_embedded_private_value ); } } } /* check next IFD mark */ // uint32 offset = get_ifd0_pos(ctif ); // uint32 IFDn = get_next_ifd_pos( ctif, offset ); // printf("IFD: offset=%i, IFD0=%i IFDn=%i ifd+count=%i\n", offset, ifd, IFDn, ifdbase+12*count); add_mem_entry( &memmap, ifdbase+12*count, 4, mt_offset_to_ifd); /* handle stripoffset data */ //printf("ifd_count=%i, stripoffset_count=%i\n", stripoffset_entry.count, stripoffset_count); uint32 stripoffset_values[stripoffset_entry.count]; switch (stripoffset_entry.datatype) { case TIFF_LONG: { /* value */ if (stripoffset_entry.value_or_offset == is_value) { for (uint32 i=0; i< stripoffset_entry.count; i++) { stripoffset_values[i] = stripoffset_entry.data32; } } /* offset */ if (stripoffset_entry.value_or_offset == is_offset) { offset_t offset; ret_t ret = read_offsetdata(ctif, stripoffset_entry.data32offset, stripoffset_entry.count, stripoffset_entry.datatype, &offset, &ret); if (ret.returncode != is_valid) { fprintf(stderr, "error reading offset data, stripoffset_entry.count has size %u, resulting address %zu, but only offset to %lu is possible\n", stripoffset_entry.count, ((uint64) stripoffset_entry.count*sizeof(uint32)), (uint64) 0xffffffff); exit(EXIT_FAILURE); } uint32 * p = offset.data32p; if ((uint64) stripoffset_entry.count*sizeof(uint32) > 0xffffffff) { fprintf(stderr, "stripoffset_entry.count has size %u, resulting address %zu, but only offset to %lu is possible\n", stripoffset_entry.count, ((uint64) stripoffset_entry.count*sizeof(uint32)), (uint64) 0xffffffff); exit(EXIT_FAILURE); } for (uint32 i=0; i< stripoffset_entry.count; i++) { uint32 pval = *p; if (is_byteswapped(ctif)) { TIFFSwabLong(&pval); } stripoffset_values[i]=pval; p++; } } break; } case TIFF_SHORT: { /* value */ if (stripoffset_entry.value_or_offset == is_value) { for (uint32 i=0; i< stripoffset_entry.count; i++) { stripoffset_values[i]= stripoffset_entry.data16[i]; } } /* offset */ if (stripoffset_entry.value_or_offset == is_offset) { offset_t offset; ret_t ret = read_offsetdata(ctif, stripoffset_entry.data32offset, stripoffset_entry.count, stripoffset_entry.datatype, &offset, &ret); if (ret.returncode != is_valid) { fprintf(stderr, "error reading offset data, stripoffset_entry.count has size %u, resulting address %zu, but only offset to %lu is possible\n", stripoffset_entry.count, ((uint64) stripoffset_entry.count*sizeof(uint32)), (uint64) 0xffffffff); exit(EXIT_FAILURE); } uint16 * p = offset.data16p; if ((uint64) stripoffset_entry.count*sizeof(uint16) > 0xffffffff) { fprintf(stderr, "stripoffset_entry.count has size %u, resulting address %zu, but only offset to %lu is possible\n", stripoffset_entry.count, ((uint64) stripoffset_entry.count*sizeof(uint16)), (uint64) 0xffffffff); exit(EXIT_FAILURE); } for (uint32 i=0; i< count; i++) { uint16 pval = *p; if (is_byteswapped(ctif)) { TIFFSwabShort(&pval); } stripoffset_values[i]=pval; p++; } } break; } default: { perror("stripoffset_entry.datatype has an unexpected value, possible a program error\n"); exit(EXIT_FAILURE); } } //printf("count=%i\n", stripoffset_entry.count); /*TODO: for (int i=0; i< stripoffset_entry.count; i++) { uint32 rawstriplen = TIFFRawStripSize(ctif->tif, i); //printf("OFFSET: p[%i]=%u len=%i\n", i,stripoffset_values[i], rawstriplen); add_mem_entry( &memmap, stripoffset_values[i], rawstriplen, mt_stripoffset_value); } */ /* sort entries by offset */ qsort(memmap.base_p, memmap.count, sizeof( mem_map_entry_t), compare_memmap); /* printf("memmap before HOLE detection\n"); print_mem_map( &memmap ); printf("----------------------------\n"); */ /* add all unused areas */ uint32 memmap_orig_count = memmap.count; for (uint32 j=1; j< memmap_orig_count; j++) { mem_map_entry_t * prev=memmap.base_p+j-1; mem_map_entry_t * act =memmap.base_p+j; uint32 estimated_offset = (prev->offset + prev->count); if (estimated_offset < act->offset) { /* found a hole */ printf("HOLE FOUND at %u\n", estimated_offset); printf("\tprev->offset=%u prev->count=%u estimated=%u\n", prev->offset, prev->count, estimated_offset); printf("\tact->offset=%u act->count=%u\n", act->offset, act->count); add_mem_entry( &memmap, estimated_offset, (act->offset -estimated_offset), mt_unused); } } /* sort entries by offset again */ qsort(memmap.base_p, memmap.count, sizeof( mem_map_entry_t), compare_memmap); /* add unused area at end */ mem_map_entry_t * last = memmap.base_p + memmap.count-1; uint32 estimated_offset = (last->offset + last->count); if (memmap.max_len > estimated_offset) { printf("HOLE (at end) FOUND at %u\n", estimated_offset); add_mem_entry( &memmap, estimated_offset, (memmap.max_len -estimated_offset), mt_unused); } /* sort entries by offset again */ qsort(memmap.base_p, memmap.count, sizeof( mem_map_entry_t), compare_memmap); return &memmap; }