Skip to content

Commit 44ba8a2

Browse files
committed
[libexif] Added character set conversion to UserComment
closes xbmc#12628
1 parent 13e3ada commit 44ba8a2

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

lib/libexif/ExifParse.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -451,11 +451,32 @@ void CExifParse::ProcessDir(const unsigned char* const DirStart,
451451

452452
case TAG_USERCOMMENT:
453453
{
454-
const int EXIF_COMMENT_HDR_LENGTH = 8; // All comment tags have 8 bytes of header info
455-
int length = max(ByteCount - EXIF_COMMENT_HDR_LENGTH, 0);
456-
length = min(length, MAX_COMMENT);
457-
strncpy(m_ExifInfo->Comments, (char *)ValuePtr+EXIF_COMMENT_HDR_LENGTH, length);
458-
// FixComment(comment); // Ensure comment is printable
454+
// The UserComment allows comments without the charset limitations of ImageDescription.
455+
// Therefore the UserComment field is prefixed by a CharacterCode field (8 Byte):
456+
// - ASCII: 'ASCII\0\0\0'
457+
// - Unicode: 'UNICODE\0'
458+
// - JIS X208-1990: 'JIS\0\0\0\0\0'
459+
// - Unknown: '\0\0\0\0\0\0\0\0' (application specific)
460+
461+
m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNKNOWN;
462+
463+
const int EXIF_COMMENT_CHARSET_LENGTH = 8;
464+
if (ByteCount >= EXIF_COMMENT_CHARSET_LENGTH)
465+
{
466+
// As some implementations use spaces instead of \0 for the padding,
467+
// we're not so strict and check only the prefix.
468+
if (memcmp(ValuePtr, "ASCII", 5) == 0)
469+
m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_ASCII;
470+
else if (memcmp(ValuePtr, "UNICODE", 7) == 0)
471+
m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNICODE;
472+
else if (memcmp(ValuePtr, "JIS", 3) == 0)
473+
m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_JIS;
474+
475+
int length = ByteCount - EXIF_COMMENT_CHARSET_LENGTH;
476+
length = min(length, MAX_COMMENT);
477+
memcpy(m_ExifInfo->Comments, ValuePtr + EXIF_COMMENT_CHARSET_LENGTH, length);
478+
// FixComment(comment); // Ensure comment is printable
479+
}
459480
}
460481
break;
461482

lib/libexif/libexif.h

+7
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ typedef struct {
7575
char ImageType[MAX_IPTC_STRING];
7676
} IPTCInfo_t;
7777

78+
#define EXIF_COMMENT_CHARSET_CONVERTED -1 // Comments contains converted data
79+
#define EXIF_COMMENT_CHARSET_UNKNOWN 0 // Exif: Unknown
80+
#define EXIF_COMMENT_CHARSET_ASCII 2 // Exif: Ascii
81+
#define EXIF_COMMENT_CHARSET_UNICODE 3 // Exif: Unicode (UTF-16)
82+
#define EXIF_COMMENT_CHARSET_JIS 4 // Exif: JIS X208-1990
83+
7884
#define MAX_COMMENT 2000
7985
#define MAX_DATE_COPIES 10
8086

@@ -101,6 +107,7 @@ typedef struct {
101107
int ExposureMode;
102108
int ISOequivalent;
103109
int LightSource;
110+
int CommentsCharset; // EXIF_COMMENT_CHARSET_*
104111
char Comments[MAX_COMMENT];
105112
char Description[MAX_COMMENT];
106113

xbmc/pictures/PictureInfoTag.cpp

+18-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "XBDateTime.h"
2323
#include "Util.h"
2424
#include "utils/Variant.h"
25+
#include "utils/CharsetConverter.h"
2526

2627
using namespace std;
2728

@@ -64,7 +65,7 @@ void CPictureInfoTag::Archive(CArchive& ar)
6465
ar << CStdString(m_exifInfo.CameraMake);
6566
ar << CStdString(m_exifInfo.CameraModel);
6667
ar << m_exifInfo.CCDWidth;
67-
ar << CStdString(m_exifInfo.Comments);
68+
ar << GetInfo(SLIDE_EXIF_COMMENT); // Store and restore the comment charset converted
6869
ar << CStdString(m_exifInfo.Description);
6970
ar << CStdString(m_exifInfo.DateTime);
7071
for (int i = 0; i < 10; i++)
@@ -128,6 +129,7 @@ void CPictureInfoTag::Archive(CArchive& ar)
128129
GetStringFromArchive(ar, m_exifInfo.CameraModel, sizeof(m_exifInfo.CameraModel));
129130
ar >> m_exifInfo.CCDWidth;
130131
GetStringFromArchive(ar, m_exifInfo.Comments, sizeof(m_exifInfo.Comments));
132+
m_exifInfo.CommentsCharset = EXIF_COMMENT_CHARSET_CONVERTED; // Store and restore the comment charset converted
131133
GetStringFromArchive(ar, m_exifInfo.Description, sizeof(m_exifInfo.Description));
132134
GetStringFromArchive(ar, m_exifInfo.DateTime, sizeof(m_exifInfo.DateTime));
133135
for (int i = 0; i < 10; i++)
@@ -191,7 +193,7 @@ void CPictureInfoTag::Serialize(CVariant& value)
191193
value["cameramake"] = CStdString(m_exifInfo.CameraMake);
192194
value["cameramodel"] = CStdString(m_exifInfo.CameraModel);
193195
value["ccdwidth"] = m_exifInfo.CCDWidth;
194-
value["comments"] = CStdString(m_exifInfo.Comments);
196+
value["comments"] = GetInfo(SLIDE_EXIF_COMMENT); // Charset conversion
195197
value["description"] = CStdString(m_exifInfo.Description);
196198
value["datetime"] = CStdString(m_exifInfo.DateTime);
197199
for (int i = 0; i < 10; i++)
@@ -302,7 +304,20 @@ const CStdString CPictureInfoTag::GetInfo(int info) const
302304
break;
303305
case SLIDE_COMMENT:
304306
case SLIDE_EXIF_COMMENT:
305-
value = m_exifInfo.Comments;
307+
// The charset used for the UserComment is stored in CommentsCharset:
308+
// Ascii, Unicode (UCS2), JIS (X208-1990), Unknown (application specific)
309+
if (m_exifInfo.CommentsCharset == EXIF_COMMENT_CHARSET_UNICODE)
310+
{
311+
g_charsetConverter.ucs2ToUTF8(CStdString16((uint16_t*)m_exifInfo.Comments), value);
312+
}
313+
else
314+
{
315+
// Ascii doesn't need to be converted (EXIF_COMMENT_CHARSET_ASCII)
316+
// Archived data is already converted (EXIF_COMMENT_CHARSET_CONVERTED)
317+
// Unknown data can't be converted as it could be any codec (EXIF_COMMENT_CHARSET_UNKNOWN)
318+
// JIS data can't be converted as CharsetConverter and iconv lacks support (EXIF_COMMENT_CHARSET_JIS)
319+
value = m_exifInfo.Comments;
320+
}
306321
break;
307322
case SLIDE_EXIF_DATE_TIME:
308323
case SLIDE_EXIF_DATE:

0 commit comments

Comments
 (0)