From c9b33b324d1376bd4789bd92ee9380c8df023cc6 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Fri, 27 Aug 2021 01:47:09 +0200
Subject: [PATCH] add codecvt support

---
 CMakeLists.txt        | 63 +++++++++++++++++++++++++----------------
 src/RagePhoto.cpp     | 33 ++++++++--------------
 src/RagePhoto.h       |  1 -
 tests/CodecvtTest.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++
 tests/IconvTest.cpp   | 66 +++++++++++++++++++++++++++++++++----------
 5 files changed, 167 insertions(+), 62 deletions(-)
 create mode 100644 tests/CodecvtTest.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7ba6196..caa554b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,53 +5,68 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
-if (WIN32)
+message("-- Testing codecvt")
+try_run(CODECVT_RUN CODECVT_COMPILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/CodecvtTest.cpp)
+if (CODECVT_COMPILE)
     list(APPEND LIBRAGEPHOTO_DEFINES
-        USE_WINAPI
+        CODECVT_COMPATIBLE
     )
+    message("-- Testing codecvt - yes")
+else()
+    message("-- Testing codecvt - no")
 endif()
 
 message("-- Testing iconv")
 try_run(ICONV_RUN ICONV_COMPILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/IconvTest.cpp)
 if (ICONV_COMPILE)
     list(APPEND LIBRAGEPHOTO_DEFINES
-        USE_ICONV
+        ICONV_COMPATIBLE
     )
     message("-- Testing iconv - yes")
 else()
     message("-- Testing iconv - no")
 endif()
 
-option(WITH_BENCHMARK "Benchmark RagePhoto Parsing Engine" OFF)
+project(ragephoto LANGUAGES CXX)
+
+set(RAGEPHOTO_SOURCES
+    src/RagePhoto.cpp
+    src/RagePhoto.h
+)
+set(RAGEPHOTO_HEADERS
+    src/libragephoto_global.h
+    src/RagePhoto.h
+)
+
+option(BUILD_SHARED "Build libragephoto as shared library" ON)
+if (BUILD_SHARED)
+    add_library(ragephoto SHARED ${RAGEPHOTO_HEADERS} ${RAGEPHOTO_SOURCES})
+    set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
+else()
+    add_library(ragephoto STATIC ${RAGEPHOTO_HEADERS} ${RAGEPHOTO_SOURCES})
+endif()
+
+option(WITH_BENCHMARK "Build with libragephoto benchmark" OFF)
 if (WITH_BENCHMARK)
     list(APPEND LIBRAGEPHOTO_DEFINES
         RAGEPHOTO_BENCHMARK
     )
 endif()
 
-project(ragephoto LANGUAGES CXX)
-add_library(ragephoto SHARED
-    src/libragephoto_global.h
-    src/RagePhoto.cpp
-    src/RagePhoto.h
-)
 target_compile_definitions(ragephoto PRIVATE
     LIBRAGEPHOTO_LIBRARY
     ${LIBRAGEPHOTO_DEFINES}
 )
 install(TARGETS ragephoto DESTINATION lib)
-install(FILES
-    src/RagePhoto.h
-    src/libragephoto_global.h
-    DESTINATION include
-)
-set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
+install(FILES ${RAGEPHOTO_HEADERS} DESTINATION include)
 
-project(ragephoto-extract LANGUAGES CXX)
-add_executable(ragephoto-extract
-    src/libragephoto_global.h
-    src/RagePhoto-Extract.cpp
-    src/RagePhoto.h
-)
-target_link_libraries(ragephoto-extract ragephoto)
-install(TARGETS ragephoto-extract DESTINATION bin)
+option(WITH_EXTRACT "Build ragephoto-extract" ON)
+if (WITH_EXTRACT)
+    project(ragephoto-extract LANGUAGES CXX)
+    set(EXTRACT_SOURCES
+        src/RagePhoto-Extract.cpp
+    )
+    add_executable(ragephoto-extract ${RAGEPHOTO_HEADERS} ${EXTRACT_SOURCES})
+    target_link_libraries(ragephoto-extract ragephoto)
+    install(TARGETS ragephoto-extract DESTINATION bin)
+endif()
diff --git a/src/RagePhoto.cpp b/src/RagePhoto.cpp
index 2624479..16a468e 100644
--- a/src/RagePhoto.cpp
+++ b/src/RagePhoto.cpp
@@ -25,8 +25,11 @@
 #include <chrono>
 #endif
 
-#ifdef USE_ICONV
-#include "iconv.h"
+#ifdef CODECVT_COMPATIBLE
+#include <codecvt>
+#include <locale>
+#elif defined ICONV_COMPATIBLE
+#include <iconv.h>
 #endif
 
 RagePhoto::RagePhoto()
@@ -81,7 +84,12 @@ bool RagePhoto::load(const char *data, size_t length)
             return false;
         }
 
-#ifdef USE_ICONV
+#ifdef CODECVT_COMPATIBLE
+        char16_t photoHeader16[128];
+        memcpy(photoHeader16, photoHeader, sizeof(char) * 256);
+        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
+        p_photoString = convert.to_bytes(photoHeader16);
+#elif defined ICONV_COMPATIBLE
         iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
         if (iconv_in == (iconv_t)-1) {
             p_error = Error::UnicodeInitError; // 4
@@ -336,19 +344,6 @@ const std::string RagePhoto::title()
     return p_titleString;
 }
 
-size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_t len)
-{
-#ifdef READ_USE_FOR
-    for (size_t i = 0; i < len; i++) {
-        output[i] = input[*pos+i];
-    }
-#else
-    memcpy(output, &input[*pos], sizeof(char) * len);
-#endif
-    *pos = *pos + len;
-    return len;
-}
-
 size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen)
 {
     size_t readLen = 0;
@@ -357,13 +352,7 @@ size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_
     readLen = inputLen - *pos;
     if (readLen > len)
         readLen = len;
-#ifdef READ_USE_FOR
-    for (size_t i = 0; i < readLen; i++) {
-        output[i] = input[*pos+i];
-    }
-#else
     memcpy(output, &input[*pos], sizeof(char) * readLen);
-#endif
     *pos = *pos + readLen;
     return readLen;
 }
diff --git a/src/RagePhoto.h b/src/RagePhoto.h
index 51e29ea..92c75d9 100644
--- a/src/RagePhoto.h
+++ b/src/RagePhoto.h
@@ -81,7 +81,6 @@ public:
     const std::string title();
 
 private:
-    inline size_t readBuffer(const char *input, char *output, size_t *pos, size_t len);
     inline size_t readBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen);
     inline uint32_t charToUInt32BE(char *x);
     inline uint32_t charToUInt32LE(char *x);
diff --git a/tests/CodecvtTest.cpp b/tests/CodecvtTest.cpp
new file mode 100644
index 0000000..5e7750e
--- /dev/null
+++ b/tests/CodecvtTest.cpp
@@ -0,0 +1,66 @@
+/*****************************************************************************
+* libragephoto RAGE Photo Parser
+* Copyright (C) 2021 Syping
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* This software is provided as-is, no warranties are given to you, we are not
+* responsible for anything with use of the software, you are self responsible.
+*****************************************************************************/
+
+#include <codecvt>
+#include <cstring>
+#include <locale>
+#include <iostream>
+
+int main(int argc, char *argv[])
+{
+    const char photoHeader[256] = {
+        0x50, 0x00, 0x48, 0x00, 0x4f, 0x00, 0x54, 0x00,
+        0x4f, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00,
+        0x30, 0x00, 0x32, 0x00, 0x2f, 0x00, 0x30, 0x00,
+        0x31, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x37, 0x00,
+        0x20, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3a, 0x00,
+        0x34, 0x00, 0x32, 0x00, 0x3a, 0x00, 0x34, 0x00,
+        0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    char16_t photoHeader16[128];
+    memcpy(photoHeader16, photoHeader, sizeof(char) * 256);
+    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
+    std::string photoString = convert.to_bytes(photoHeader16);
+    std::cout << photoString << std::endl;
+    return strcmp(photoString.c_str(), "PHOTO - 02/01/17 08:42:44");
+}
diff --git a/tests/IconvTest.cpp b/tests/IconvTest.cpp
index 0357d8a..98549e4 100644
--- a/tests/IconvTest.cpp
+++ b/tests/IconvTest.cpp
@@ -16,22 +16,58 @@
 * responsible for anything with use of the software, you are self responsible.
 *****************************************************************************/
 
-#include "iconv.h"
-#include "stdio.h"
+#include <cstdio>
+#include <cstring>
+#include <iconv.h>
 
 int main(int argc, char *argv[])
 {
-    iconv_t instance = iconv_open("UTF-16LE", "UTF-8");
-    if (instance == (iconv_t)-1)
-        return 1;
-    char src[] = "Test";
-    char dst[256];
-    size_t src_s = sizeof(src);
-    size_t dst_s = sizeof(dst);
-    char *isrc = src;
-    char *idst = dst;
-    iconv(instance, &isrc, &src_s, &idst, &dst_s);
-    iconv_close(instance);
-    printf("%s\n", dst);
-    return 0;
+    char photoHeader[256] = {
+        0x50, 0x00, 0x48, 0x00, 0x4f, 0x00, 0x54, 0x00,
+        0x4f, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00,
+        0x30, 0x00, 0x32, 0x00, 0x2f, 0x00, 0x30, 0x00,
+        0x31, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x37, 0x00,
+        0x20, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3a, 0x00,
+        0x34, 0x00, 0x32, 0x00, 0x3a, 0x00, 0x34, 0x00,
+        0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    char photoString[256];
+    iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
+    if (iconv_in == (iconv_t)-1)
+        return -1;
+    size_t src_s = sizeof(photoHeader);
+    size_t dst_s = sizeof(photoString);
+    char *src = photoHeader;
+    char *dst = photoString;
+    size_t ret = iconv(iconv_in, &src, &src_s, &dst, &dst_s);
+    iconv_close(iconv_in);
+    if (ret == static_cast<size_t>(-1)) {
+        return -1;
+    }
+    return strcmp(photoString, "PHOTO - 02/01/17 08:42:44");
 }