static void format_debug_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level) { guint tag; guint type; guint count; guint segment; guint seg_len; tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo); type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo); count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo); seg_len = ExifFormatList[type].size * count; if (seg_len > 4) { segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo); if (segment + seg_len > len) return; } else { segment = offset + EXIF_TIFD_OFFSET_DATA; } log_printf("%*stag:0x%04X (%05d), type:%2d %9s, len:%6d [%02X %02X %02X %02X] @ offset:%d\n", level, "", tag, tag, type, (type < EXIF_FORMAT_COUNT) ? ExifFormatList[type].short_name : "???", count, data[segment], data[segment + 1], data[segment + 2], data[segment + 3], segment); if (tag == 0x8769 || tag == 0x14a) { gint i; log_printf("%*s~~~ found %s table\n", level, "", (tag == 0x14a) ? "subIFD" : "EXIF" ); for (i = 0; i < count; i++) { guint subset; subset = exif_byte_get_int32(data + segment + i * 4, bo); format_debug_tiff_table(data, len, subset, bo, level + 1); } } else if (tag == 0x8773 && type == EXIF_FORMAT_UNDEFINED) { log_printf("%*s~~~ found ICC color profile at offset %d, length %d\n", level, "", segment, seg_len); } else if (tag == 0x201 && (type == EXIF_FORMAT_LONG_UNSIGNED || type == EXIF_FORMAT_LONG)) { guint subset = exif_byte_get_int32(data + segment, bo); log_printf("%*s~~~ found jpeg data at offset %d\n", level, "", subset); } else if (tag == 0x202 && (type == EXIF_FORMAT_LONG_UNSIGNED || type == EXIF_FORMAT_LONG)) { guint subset = exif_byte_get_int32(data + segment, bo); log_printf("%*s~~~ found jpeg data length of %d\n", level, "", subset); } }
static void nikon_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len) { guint tag; guint type; guint count; guint segment; guint seg_len; tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo); type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo); count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo); /* so far, we only care about tags with type long */ if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return; seg_len = ExifFormatList[type].size * count; if (seg_len > 4) { segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo); if (segment + seg_len > len) return; } else { segment = offset + EXIF_TIFD_OFFSET_DATA; } if (tag == 0x14a) { /* sub IFD table */ guint i; for (i = 0; i < count; i++) { guint subset; subset = exif_byte_get_int32(data + segment + i * 4, bo); nikon_tiff_table(data, len, subset, bo, level + 1, image_offset, image_length); } } else if (tag == 0x201) { /* jpeg data start offset */ *jpeg_start = exif_byte_get_int32(data + segment, bo); } else if (tag == 0x202) { /* jpeg data length */ *jpeg_len = exif_byte_get_int32(data + segment, bo); } }
static guint tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo, guint tag, ExifFormatType type, guint *result_offset, guint *result_count) { guint count; guint i; if (len < offset + 2) return 0; if (type > EXIF_FORMAT_COUNT) return 0; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * 12 + 4) return 0; for (i = 0; i < count; i++) { guint segment; segment = offset + i * 12; if (exif_byte_get_int16(data + segment, bo) == tag && exif_byte_get_int16(data + segment + 2, bo) == type) { guint chunk_count; guint chunk_offset; guint chunk_length; chunk_count = exif_byte_get_int32(data + segment + 4, bo); chunk_length = ExifFormatList[type].size * chunk_count; if (chunk_length > 4) { chunk_offset = exif_byte_get_int32(data + segment + 8, bo); } else { chunk_offset = segment + 8; } if (chunk_offset + chunk_length <= len) { *result_offset = chunk_offset; *result_count = chunk_count; } return 0; } } return exif_byte_get_int32(data + offset + count * 12, bo); }
static guint format_debug_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level) { guint count; guint i; if (level > EXIF_TIFF_MAX_LEVELS) return 0; if (len < offset + 2) return FALSE; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0; log_printf("%*s== tiff table #%d has %d entries ==\n", level, "", level, count); for (i = 0; i < count; i++) { format_debug_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level); } log_printf("%*s----------- end of #%d ------------\n", level, "", level); return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo); }
gint format_olympus_raw(unsigned char *data, const guint len, guint *image_offset, guint *exif_offset) { guint i_off = 0; guint e_off = 0; guint offset; gint level; if (len < 8) return FALSE; /* these are in tiff file format with a different magick header */ if (memcmp(data, "IIR", 3) != 0) return FALSE; offset = exif_byte_get_int32(data + 4, EXIF_BYTE_ORDER_INTEL); level = 0; while (offset && level < EXIF_TIFF_MAX_LEVELS) { offset = olympus_tiff_table(data, len, offset, EXIF_BYTE_ORDER_INTEL, 0, &i_off, &e_off); level++; } if (i_off != 0 || e_off != 0) { if (image_offset) *image_offset = i_off; if (exif_offset) *exif_offset = e_off; return TRUE; } return FALSE; }
static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *image_length) { guint count; guint i; guint jpeg_start = 0; guint jpeg_len = 0; /* limit damage from infinite loops */ if (level > EXIF_TIFF_MAX_LEVELS) return 0; if (len < offset + 2) return FALSE; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0; for (i = 0; i < count; i++) { nikon_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level, image_offset, image_length, &jpeg_start, &jpeg_len); } if (jpeg_start > 0 && jpeg_len > *image_length) { *image_offset = jpeg_start; *image_length = jpeg_len; } return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo); }
gint format_fuji_raw(unsigned char *data, const guint len, guint *image_offset, guint *exif_offset) { guint io; guint eo; if (len < 128 || memcmp(data, "FUJIFILM", 8) != 0) { return FALSE; } /* offset to jpeg is embedded at bytes 84-87 */ io = exif_byte_get_int32(data + 84, EXIF_BYTE_ORDER_MOTOROLA); if (io + 4 > len) return FALSE; /* verify jpeg marker */ if (memcmp(data + io, "\xff\xd8\xff\xe1", 4) != 0) { return FALSE; } /* Exif is stored in the jpeg, so use the same offset */ eo=io; if (image_offset) *image_offset = io; if (exif_offset) *exif_offset = eo; return TRUE; }
gint format_fuji_makernote(ExifData *exif, unsigned char *tiff, guint offset, guint size, ExifByteOrder bo) { unsigned char *data; guint ifdstart; if (offset + 8 + 4 >= size) return FALSE; data = tiff + offset; /* Fuji tag format starts with "FUJIFILM", * followed by 4 bytes indicating offset to IFD directory using Fuji tags, * byte order is always little endian (II). */ if (memcmp(data, "FUJIFILM", 8) != 0) return FALSE; ifdstart = exif_byte_get_int32(data + 8, EXIF_BYTE_ORDER_INTEL); if (offset + ifdstart >= size) return FALSE; if (exif_parse_IFD_table(exif, tiff + offset, ifdstart, size - offset, EXIF_BYTE_ORDER_INTEL, 0, FujiExifMarkersList) != 0) { return FALSE; } return TRUE; }
static void olympus_tiff_entry(unsigned char *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *exif_offset) { guint tag; guint type; guint count; guint segment; guint seg_len; tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo); type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo); count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo); /* so far, we only care about tags with type long */ if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return; seg_len = ExifFormatList[type].size * count; if (seg_len > 4) { segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo); if (segment + seg_len > len) return; } else { segment = offset + EXIF_TIFD_OFFSET_DATA; } if (tag == 0x201) { /* start of embedded jpeg, not all olympus cameras embed a jpeg */ *image_offset = exif_byte_get_int32(data + segment, bo); } if (tag == 0x8769) { /* This is the Exif info */ *exif_offset = exif_byte_get_int32(data + segment, bo); } }
static gboolean format_tiff_find_tag_data(guchar *data, const guint len, guint tag, ExifFormatType type, guint *result_offset, guint *result_count) { ExifByteOrder bo; guint offset; if (len < 8) return FALSE; if (memcmp(data, "II", 2) == 0) { bo = EXIF_BYTE_ORDER_INTEL; } else if (memcmp(data, "MM", 2) == 0) { bo = EXIF_BYTE_ORDER_MOTOROLA; } else { return FALSE; } if (exif_byte_get_int16(data + 2, bo) != 0x002A) { return FALSE; } offset = exif_byte_get_int32(data + 4, bo); while (offset != 0) { guint ro = 0; guint rc = 0; offset = tiff_table(data, len, offset, bo, tag, type, &ro, &rc); if (ro != 0) { *result_offset = ro; *result_count = rc; return TRUE; } } return FALSE; }
gboolean format_debug_tiff_raw(guchar *data, const guint len, guint *image_offset, guint *exif_offset) { ExifByteOrder bo; gint level; guint offset; if (len < 8) return FALSE; /* for debugging, we are more relaxed as to magic header */ if (memcmp(data, "II", 2) == 0) { bo = EXIF_BYTE_ORDER_INTEL; } else if (memcmp(data, "MM", 2) == 0) { bo = EXIF_BYTE_ORDER_MOTOROLA; } else { return FALSE; } log_printf("*** debug parsing tiff\n"); offset = exif_byte_get_int32(data + 4, bo); level = 0; while (offset && level < EXIF_TIFF_MAX_LEVELS) { offset = format_debug_tiff_table(data, len, offset, bo, 0); level++; } log_printf("*** end\n"); /* we are debugging, not trying to return any data */ return FALSE; }
static guint olympus_tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder bo, gint level, guint *image_offset, guint *exif_offset) { guint count; guint i; if (level > EXIF_TIFF_MAX_LEVELS) return 0; if (len < offset + 2) return FALSE; count = exif_byte_get_int16(data + offset, bo); offset += 2; if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0; for (i = 0; i < count; i++) { olympus_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level, image_offset, exif_offset); } return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo); }