Fix decoding of Windows XP proprietary tags on big-endian machines.
authorDan Fandrich <dan@coneharvesters.com>
Tue, 5 Nov 2019 15:18:02 +0000 (16:18 +0100)
committerDan Fandrich <dan@coneharvesters.com>
Tue, 5 Nov 2019 15:18:02 +0000 (16:18 +0100)
Reported by Thorsten Otto.  Fixes #22.

libexif/exif-entry.c
libexif/exif-utils.c
libexif/exif-utils.h

index a224ac2..8b213de 100644 (file)
@@ -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 */
index f375de1..9083ddc 100644 (file)
@@ -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;
 }
index 7861564..dac701a 100644 (file)
@@ -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. */