From b7ba7cbd6e5a0e590a6ad018eaf3be1342e96d94 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Mon, 12 Aug 2013 19:32:40 +0200 Subject: avcodec/tiff: Refactor TIFF tag related functions to share the code. Signed-off-by: Michael Niedermayer --- libavcodec/tiff.c | 208 +++++++----------------------------------------------- 1 file changed, 27 insertions(+), 181 deletions(-) (limited to 'libavcodec/tiff.c') diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 2e06e3ff0e..ac7ac6016e 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -70,38 +70,6 @@ typedef struct TiffContext { TiffGeoTag *geotags; } TiffContext; -static unsigned tget_short(GetByteContext *gb, int le) -{ - unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb); - return v; -} - -static unsigned tget_long(GetByteContext *gb, int le) -{ - unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb); - return v; -} - -static double tget_double(GetByteContext *gb, int le) -{ - av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)}; - return i.f64; -} - -static unsigned tget(GetByteContext *gb, int type, int le) -{ - switch (type) { - case TIFF_BYTE: - return bytestream2_get_byte(gb); - case TIFF_SHORT: - return tget_short(gb, le); - case TIFF_LONG: - return tget_long(gb, le); - default: - return UINT_MAX; - } -} - static void free_geotags(TiffContext *const s) { int i; @@ -245,111 +213,13 @@ static char *doubles2str(double *dp, int count, const char *sep) return ap0; } -static char *shorts2str(int16_t *sp, int count, const char *sep) -{ - int i; - char *ap, *ap0; - uint64_t component_len; - if (!sep) sep = ", "; - component_len = 7LL + strlen(sep); - if (count >= (INT_MAX - 1)/component_len) - return NULL; - ap = av_malloc(component_len * count + 1); - if (!ap) - return NULL; - ap0 = ap; - ap[0] = '\0'; - for (i = 0; i < count; i++) { - unsigned l = snprintf(ap, component_len, "%d%s", sp[i], sep); - if (l >= component_len) { - av_free(ap0); - return NULL; - } - ap += l; - } - ap0[strlen(ap0) - strlen(sep)] = '\0'; - return ap0; -} - -static int add_doubles_metadata(int count, - const char *name, const char *sep, - TiffContext *s, AVFrame *frame) -{ - char *ap; - int i; - double *dp; - - if (count >= INT_MAX / sizeof(int64_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) - return AVERROR_INVALIDDATA; - - dp = av_malloc(count * sizeof(double)); - if (!dp) - return AVERROR(ENOMEM); - - for (i = 0; i < count; i++) - dp[i] = tget_double(&s->gb, s->le); - ap = doubles2str(dp, count, sep); - av_freep(&dp); - if (!ap) - return AVERROR(ENOMEM); - av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - -static int add_shorts_metadata(int count, const char *name, - const char *sep, TiffContext *s, AVFrame *frame) -{ - char *ap; - int i; - int16_t *sp; - - if (count >= INT_MAX / sizeof(int16_t) || count <= 0) - return AVERROR_INVALIDDATA; - if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t)) - return AVERROR_INVALIDDATA; - - sp = av_malloc(count * sizeof(int16_t)); - if (!sp) - return AVERROR(ENOMEM); - - for (i = 0; i < count; i++) - sp[i] = tget_short(&s->gb, s->le); - ap = shorts2str(sp, count, sep); - av_freep(&sp); - if (!ap) - return AVERROR(ENOMEM); - av_dict_set(avpriv_frame_get_metadatap(frame), name, ap, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - -static int add_string_metadata(int count, const char *name, - TiffContext *s, AVFrame *frame) -{ - char *value; - - if (bytestream2_get_bytes_left(&s->gb) < count || count < 0) - return AVERROR_INVALIDDATA; - - value = av_malloc(count + 1); - if (!value) - return AVERROR(ENOMEM); - - bytestream2_get_bufferu(&s->gb, value, count); - value[count] = 0; - - av_dict_set(avpriv_frame_get_metadatap(frame), name, value, AV_DICT_DONT_STRDUP_VAL); - return 0; -} - static int add_metadata(int count, int type, const char *name, const char *sep, TiffContext *s, AVFrame *frame) { switch(type) { - case TIFF_DOUBLE: return add_doubles_metadata(count, name, sep, s, frame); - case TIFF_SHORT : return add_shorts_metadata(count, name, sep, s, frame); - case TIFF_STRING: return add_string_metadata(count, name, s, frame); + case TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); + case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); + case TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, avpriv_frame_get_metadatap(frame)); default : return AVERROR_INVALIDDATA; }; } @@ -702,14 +572,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) uint32_t *pal; double *dp; - tag = tget_short(&s->gb, s->le); - type = tget_short(&s->gb, s->le); - count = tget_long(&s->gb, s->le); - start = bytestream2_tell(&s->gb) + 4; - - if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) { - av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n", - type); + ret = ff_tread_tag(&s->gb, s->le, &tag, &type, &count, &start); + if (ret < 0) { goto end; } @@ -717,10 +581,10 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) switch (type) { case TIFF_BYTE: case TIFF_SHORT: - value = tget(&s->gb, type, s->le); + value = ff_tget(&s->gb, type, s->le); break; case TIFF_LONG: - off = tget_long(&s->gb, s->le); + off = ff_tget_long(&s->gb, s->le); value = off; break; case TIFF_STRING: @@ -728,14 +592,12 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) break; } default: - off = tget_long(&s->gb, s->le); + off = bytestream2_tell(&s->gb); value = UINT_MAX; - bytestream2_seek(&s->gb, off, SEEK_SET); } } else { if (type_sizes[type] * count > 4) { - off = tget_long(&s->gb, s->le); - bytestream2_seek(&s->gb, off, SEEK_SET); + off = bytestream2_tell(&s->gb); } } @@ -768,7 +630,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count) return AVERROR_INVALIDDATA; for (i = 0; i < count; i++) - s->bpp += tget(&s->gb, type, s->le); + s->bpp += ff_tget(&s->gb, type, s->le); break; default: s->bpp = -1; @@ -908,7 +770,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) for (i = 0; i < count / 3; i++) { if (k == 2) pal[i] = 0xFFU << 24; - j = (tget(&s->gb, type, s->le) >> off) << (k * 8); + j = (ff_tget(&s->gb, type, s->le) >> off) << (k * 8); pal[i] |= j; } } @@ -942,7 +804,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_GEO_KEY_DIRECTORY: ADD_METADATA(1, "GeoTIFF_Version", NULL); ADD_METADATA(2, "GeoTIFF_Key_Revision", "."); - s->geotag_count = tget_short(&s->gb, s->le); + s->geotag_count = ff_tget_short(&s->gb, s->le); if (s->geotag_count > count / 4 - 1) { s->geotag_count = count / 4 - 1; av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n"); @@ -958,14 +820,14 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) goto end; } for (i = 0; i < s->geotag_count; i++) { - s->geotags[i].key = tget_short(&s->gb, s->le); - s->geotags[i].type = tget_short(&s->gb, s->le); - s->geotags[i].count = tget_short(&s->gb, s->le); + s->geotags[i].key = ff_tget_short(&s->gb, s->le); + s->geotags[i].type = ff_tget_short(&s->gb, s->le); + s->geotags[i].count = ff_tget_short(&s->gb, s->le); if (!s->geotags[i].type) - s->geotags[i].val = get_geokey_val(s->geotags[i].key, tget_short(&s->gb, s->le)); + s->geotags[i].val = get_geokey_val(s->geotags[i].key, ff_tget_short(&s->gb, s->le)); else - s->geotags[i].offset = tget_short(&s->gb, s->le); + s->geotags[i].offset = ff_tget_short(&s->gb, s->le); } break; case TIFF_GEO_DOUBLE_PARAMS: @@ -979,7 +841,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) goto end; } for (i = 0; i < count; i++) - dp[i] = tget_double(&s->gb, s->le); + dp[i] = ff_tget_double(&s->gb, s->le); for (i = 0; i < s->geotag_count; i++) { if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) { if (s->geotags[i].count == 0 @@ -1075,7 +937,7 @@ static int decode_frame(AVCodecContext *avctx, TiffContext *const s = avctx->priv_data; AVFrame *const p = data; unsigned off; - int id, le, ret, plane, planes; + int le, ret, plane, planes; int i, j, entries, stride; unsigned soff, ssize; uint8_t *dst; @@ -1085,15 +947,11 @@ static int decode_frame(AVCodecContext *avctx, bytestream2_init(&s->gb, avpkt->data, avpkt->size); // parse image header - if (avpkt->size < 8) - return AVERROR_INVALIDDATA; - id = bytestream2_get_le16u(&s->gb); - if (id == 0x4949) - le = 1; - else if (id == 0x4D4D) - le = 0; - else { - av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n"); + if ((ret = ff_tdecode_header(&s->gb, &le, &off))) { + av_log(avctx, AV_LOG_ERROR, "Invalid TIFF header\n"); + return ret; + } else if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { + av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); return AVERROR_INVALIDDATA; } s->le = le; @@ -1104,23 +962,11 @@ static int decode_frame(AVCodecContext *avctx, s->fill_order = 0; free_geotags(s); - // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number - // that further identifies the file as a TIFF file" - if (tget_short(&s->gb, le) != 42) { - av_log(avctx, AV_LOG_ERROR, - "The answer to life, universe and everything is not correct!\n"); - return AVERROR_INVALIDDATA; - } // Reset these offsets so we can tell if they were set this frame s->stripsizesoff = s->strippos = 0; /* parse image file directory */ - off = tget_long(&s->gb, le); - if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { - av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); - return AVERROR_INVALIDDATA; - } bytestream2_seek(&s->gb, off, SEEK_SET); - entries = tget_short(&s->gb, le); + entries = ff_tget_short(&s->gb, le); if (bytestream2_get_bytes_left(&s->gb) < entries * 12) return AVERROR_INVALIDDATA; for (i = 0; i < entries; i++) { @@ -1180,12 +1026,12 @@ static int decode_frame(AVCodecContext *avctx, dst = p->data[plane]; for (i = 0; i < s->height; i += s->rps) { if (s->stripsizesoff) - ssize = tget(&stripsizes, s->sstype, s->le); + ssize = ff_tget(&stripsizes, s->sstype, s->le); else ssize = s->stripsize; if (s->strippos) - soff = tget(&stripdata, s->sot, s->le); + soff = ff_tget(&stripdata, s->sot, s->le); else soff = s->stripoff; -- cgit v1.2.3