From 0f231cddd210d6e84a93292530e09f539462fde8 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Tue, 5 Nov 2019 16:18:02 +0100 Subject: [PATCH] Fix decoding of Windows XP proprietary tags on big-endian machines. Reported by Thorsten Otto. Fixes #22. --- libexif/exif-entry.c | 13 ++++++++----- libexif/exif-utils.c | 24 ++++++++++++++---------- libexif/exif-utils.h | 2 +- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/libexif/exif-entry.c b/libexif/exif-entry.c index a224ac2..8b213de 100644 --- a/libexif/exif-entry.c +++ b/libexif/exif-entry.c @@ -1368,21 +1368,24 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen) case EXIF_TAG_XP_KEYWORDS: case EXIF_TAG_XP_SUBJECT: { - unsigned short *utf16; + unsigned char *utf16; /* Sanity check the size to prevent overflow */ - if (e->size+sizeof(unsigned short) < e->size) break; + if (e->size+sizeof(uint16_t)+1 < e->size) break; /* The tag may not be U+0000-terminated , so make a local U+0000-terminated copy before converting it */ - utf16 = exif_mem_alloc (e->priv->mem, e->size+sizeof(unsigned short)); + utf16 = exif_mem_alloc (e->priv->mem, e->size+sizeof(uint16_t)+1); if (!utf16) break; memcpy(utf16, e->data, e->size); /* NUL terminate the string. If the size is odd (which isn't possible - * for a UTF16 string), then this will overwrite the final garbage byte. + * for a valid UTF16 string), then this will overwrite the high byte of + * the final half word, plus add a full zero NUL word at the end. */ - utf16[e->size/sizeof(unsigned short)] = 0; + utf16[e->size] = 0; + utf16[e->size+1] = 0; + utf16[e->size+2] = 0; /* Warning! The texts are converted from UTF16 to UTF8 */ /* FIXME: use iconv to convert into the locale encoding */ diff --git a/libexif/exif-utils.c b/libexif/exif-utils.c index f375de1..9083ddc 100644 --- a/libexif/exif-utils.c +++ b/libexif/exif-utils.c @@ -217,37 +217,41 @@ exif_set_srational (unsigned char *buf, ExifByteOrder order, * It should really be replaced by iconv(). */ void -exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen) +exif_convert_utf16_to_utf8 (char *out, const unsigned char *in, int maxlen) { if (maxlen <= 0) { return; } - while (*in) { - if (*in < 0x80) { + for (;;) { + ExifShort v = exif_get_short(in, EXIF_BYTE_ORDER_INTEL); + if (!v) + break; + if (v < 0x80) { if (maxlen > 1) { - *out++ = (char)*in++; + *out++ = (char)v; maxlen--; } else { break; } - } else if (*in < 0x800) { + } else if (v < 0x800) { if (maxlen > 2) { - *out++ = ((*in >> 6) & 0x1F) | 0xC0; - *out++ = (*in++ & 0x3F) | 0x80; + *out++ = ((v >> 6) & 0x1F) | 0xC0; + *out++ = (v & 0x3F) | 0x80; maxlen -= 2; } else { break; } } else { if (maxlen > 3) { - *out++ = ((*in >> 12) & 0x0F) | 0xE0; - *out++ = ((*in >> 6) & 0x3F) | 0x80; - *out++ = (*in++ & 0x3F) | 0x80; + *out++ = ((v >> 12) & 0x0F) | 0xE0; + *out++ = ((v >> 6) & 0x3F) | 0x80; + *out++ = (v & 0x3F) | 0x80; maxlen -= 3; } else { break; } } + in += 2; } *out = 0; } diff --git a/libexif/exif-utils.h b/libexif/exif-utils.h index 7861564..dac701a 100644 --- a/libexif/exif-utils.h +++ b/libexif/exif-utils.h @@ -168,7 +168,7 @@ void exif_set_srational (unsigned char *b, ExifByteOrder order, ExifSRational value); /*! \internal */ -void exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen); +void exif_convert_utf16_to_utf8 (char *out, const unsigned char *in, int maxlen); /* Please do not use this function outside of the library. */ -- 2.7.4