[{"id":14721,"web_url":"https://patchwork.libcamera.org/comment/14721/","msgid":"<YAvX5OkJ3E72tMkb@pendragon.ideasonboard.com>","date":"2021-01-23T08:01:40","subject":"Re: [libcamera-devel] [PATCH v3 1/8] android: jpeg: exif: Expand\n\tsetString to support different encodings","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch.\n\nOn Sat, Jan 23, 2021 at 02:16:57PM +0900, Paul Elder wrote:\n> GPSProcessingMethod and UserComment in EXIF tags can be in UTF-16.\n> Expand setString to take an encoding when the field type is undefined.\n> Update callers accordingly.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n> ---\n> Changes in v3:\n> - use array to contain string encoding codes\n> - drop JIS and Undefined\n> - clean up setString a bit\n> - use the endianness of the exif\n> \n> Changes in v2:\n> - moved from utils into exif\n> - support no-encoding\n> ---\n>  src/android/jpeg/exif.cpp | 88 +++++++++++++++++++++++++++++++++++----\n>  src/android/jpeg/exif.h   | 10 ++++-\n>  2 files changed, 89 insertions(+), 9 deletions(-)\n> \n> diff --git a/src/android/jpeg/exif.cpp b/src/android/jpeg/exif.cpp\n> index 33b3fa7f..5d9492fb 100644\n> --- a/src/android/jpeg/exif.cpp\n> +++ b/src/android/jpeg/exif.cpp\n> @@ -7,6 +7,9 @@\n>  \n>  #include \"exif.h\"\n>  \n> +#include <map>\n> +#include <uchar.h>\n> +\n>  #include \"libcamera/internal/log.h\"\n>  #include \"libcamera/internal/utils.h\"\n>  \n> @@ -178,11 +181,18 @@ void Exif::setRational(ExifIfd ifd, ExifTag tag, ExifRational item)\n>  \texif_entry_unref(entry);\n>  }\n>  \n> -void Exif::setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::string &item)\n> +static const std::map<Exif::StringEncoding, std::array<uint8_t, 8>> stringEncodingCodes = {\n> +\t{ Exif::ASCII,     { 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00 } },\n> +\t{ Exif::Unicode,   { 0x55, 0x4e, 0x49, 0x43, 0x4f, 0x44, 0x45, 0x00 } },\n> +};\n> +\n> +void Exif::setString(ExifIfd ifd, ExifTag tag, ExifFormat format,\n> +\t\t     const std::string &item, StringEncoding encoding)\n>  {\n>  \tstd::string ascii;\n>  \tsize_t length;\n>  \tconst char *str;\n> +\tstd::vector<uint8_t> buf;\n>  \n>  \tif (format == EXIF_FORMAT_ASCII) {\n>  \t\tascii = utils::toAscii(item);\n> @@ -191,13 +201,47 @@ void Exif::setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::str\n>  \t\t/* Pad 1 extra byte to null-terminate the ASCII string. */\n>  \t\tlength = ascii.length() + 1;\n>  \t} else {\n> -\t\tstr = item.c_str();\n> -\n> -\t\t/*\n> -\t\t * Strings stored in different formats (EXIF_FORMAT_UNDEFINED)\n> -\t\t * are not null-terminated.\n> -\t\t */\n> -\t\tlength = item.length();\n> +\t\tstd::u16string u16str;\n> +\n> +\t\tauto encodingString = stringEncodingCodes.find(encoding);\n> +\t\tif (encodingString != stringEncodingCodes.end()) {\n> +\t\t\tbuf = {\n> +\t\t\t\tencodingString->second.begin(),\n> +\t\t\t\tencodingString->second.end()\n> +\t\t\t};\n> +\t\t}\n> +\n> +\t\tswitch (encoding) {\n> +\t\tcase Unicode:\n> +\t\t\tu16str = utf8ToUtf16(item);\n> +\n> +\t\t\tbuf.resize(8 + u16str.size() * 2);\n> +\t\t\tfor (size_t i = 0; i < u16str.size(); i++) {\n> +\t\t\t\tif (order_ == EXIF_BYTE_ORDER_INTEL) {\n> +\t\t\t\t\tbuf[8 + 2 * i] = (u16str[i] & 0xff);\n\nYou can drop the outer parentheses here and below.\n\n> +\t\t\t\t\tbuf[8 + 2 * i + 1] = ((u16str[i] >> 8) & 0xff);\n> +\t\t\t\t} else {\n> +\t\t\t\t\tbuf[8 + 2 * i] = ((u16str[i] >> 8) & 0xff);\n> +\t\t\t\t\tbuf[8 + 2 * i + 1] = (u16str[i] & 0xff);\n> +\t\t\t\t}\n> +\t\t\t}\n> +\n> +\t\t\tstr = reinterpret_cast<const char *>(buf.data());\n> +\t\t\tlength = buf.size();\n> +\n> +\t\t\tbreak;\n\nBlank line here ?\n\n> +\t\tcase ASCII:\n> +\t\tcase NoEncoding:\n> +\t\t\tbuf.insert(buf.end(), item.begin(), item.end());\n> +\t\t\tstr = reinterpret_cast<const char *>(buf.data());\n> +\n> +\t\t\t/*\n> +\t\t\t * Strings stored in different formats (EXIF_FORMAT_UNDEFINED)\n> +\t\t\t * are not null-terminated.\n> +\t\t\t */\n> +\t\t\tlength = buf.size();\n\nThe str assignment, comment, and length assignment are common to all\ncases, you can move them after th switch.\n\n> +\t\t\tbreak;\n> +\t\t}\n>  \t}\n>  \n>  \tExifEntry *entry = createEntry(ifd, tag, format, length, length);\n> @@ -290,6 +334,34 @@ void Exif::setThumbnail(Span<const unsigned char> thumbnail,\n>  \tsetShort(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);\n>  }\n>  \n> +/**\n> + * \\brief Convert UTF-8 string to UTF-16 string\n> + * \\param[in] str String to convert\n> + *\n> + * \\return \\a str in UTF-16\n> + */\n> +std::u16string Exif::utf8ToUtf16(const std::string &str)\n> +{\n> +\tmbstate_t state{};\n> +\tchar16_t c16;\n> +\tconst char *ptr = str.data();\n> +\tconst char *end = ptr + str.size();\n> +\n> +\tstd::u16string ret;\n> +\twhile (size_t rc = mbrtoc16(&c16, ptr, end - ptr + 1, &state)) {\n> +\t\tif (rc == static_cast<size_t>(-2) ||\n> +\t\t    rc == static_cast<size_t>(-1))\n> +\t\t\tbreak;\n> +\n> +\t\tret.push_back(c16);\n> +\n> +\t\tif (rc > 0)\n> +\t\t\tptr += rc;\n> +\t}\n> +\n> +\treturn ret;\n> +}\n> +\n>  [[nodiscard]] int Exif::generate()\n>  {\n>  \tif (exifData_) {\n> diff --git a/src/android/jpeg/exif.h b/src/android/jpeg/exif.h\n> index 5cab4559..73f231b2 100644\n> --- a/src/android/jpeg/exif.h\n> +++ b/src/android/jpeg/exif.h\n> @@ -26,6 +26,12 @@ public:\n>  \t\tJPEG = 6,\n>  \t};\n>  \n> +\tenum StringEncoding {\n> +\t\tNoEncoding = 0,\n> +\t\tASCII = 1,\n> +\t\tUnicode = 2,\n> +\t};\n> +\n>  \tvoid setMake(const std::string &make);\n>  \tvoid setModel(const std::string &model);\n>  \n> @@ -46,9 +52,11 @@ private:\n>  \tvoid setShort(ExifIfd ifd, ExifTag tag, uint16_t item);\n>  \tvoid setLong(ExifIfd ifd, ExifTag tag, uint32_t item);\n>  \tvoid setString(ExifIfd ifd, ExifTag tag, ExifFormat format,\n> -\t\t       const std::string &item);\n> +\t\t       const std::string &item, StringEncoding encoding = NoEncoding);\n\nMaybe a line break ?\n\nThose are all minor comments, once addressed,\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n>  \tvoid setRational(ExifIfd ifd, ExifTag tag, ExifRational item);\n>  \n> +\tstd::u16string utf8ToUtf16(const std::string &str);\n> +\n>  \tbool valid_;\n>  \n>  \tExifData *data_;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (unknown [92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 5CE2FBD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 23 Jan 2021 08:06:23 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9321F68283;\n\tSat, 23 Jan 2021 09:02:01 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AAE3B6010B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 23 Jan 2021 09:02:00 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0641B4FB;\n\tSat, 23 Jan 2021 09:01:59 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"I2vQa5JM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1611388920;\n\tbh=1mwFgfm+hc8Dsy7YK0qIE0wCRZMKo8hSH7qPpOH4izI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=I2vQa5JMMKUMmmcIehS7uCSM5wcwa5ScHvbvvaSfBDeYdHL8Pol/ir3avpknvZhqq\n\tq7bzXTHgQrxnmDThAa5K1uIsJ8cq/rW6C6Z9H2O383G72YXbLFIR3+fej8Iuw1waJN\n\tVY3SBvrkpMfUVk2xF5iEh7IPr1mogdz+bRHlc5WU=","Date":"Sat, 23 Jan 2021 10:01:40 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<YAvX5OkJ3E72tMkb@pendragon.ideasonboard.com>","References":"<20210123051704.188117-1-paul.elder@ideasonboard.com>\n\t<20210123051704.188117-2-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210123051704.188117-2-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 1/8] android: jpeg: exif: Expand\n\tsetString to support different encodings","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]