diff --git a/CMakeLists.txt b/CMakeLists.txt index e5d3d18..b3998bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,17 @@ else() message("-- Testing iconv - no") endif() +message("-- Testing wincvt") +try_run(WINCVT_RUN WINCVT_COMPILE ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests/WincvtTest.cpp) +if (WINCVT_COMPILE AND WINCVT_RUN EQUAL 0) + list(APPEND LIBRAGEPHOTO_DEFINES + WINCVT_COMPATIBLE + ) + message("-- Testing wincvt - yes") +else() + message("-- Testing wincvt - no") +endif() + # RagePhoto Source files set(RAGEPHOTO_HEADERS src/RagePhoto.h diff --git a/examples/ragephoto-qtviewer/src/main.cpp b/examples/ragephoto-qtviewer/src/main.cpp index 44f71e0..d242199 100644 --- a/examples/ragephoto-qtviewer/src/main.cpp +++ b/examples/ragephoto-qtviewer/src/main.cpp @@ -34,6 +34,7 @@ bool readPhotoFile(const QString &filename, QMainWindow *mainWindow, QLabel *pho QFile file(filename); if (file.open(QIODevice::ReadOnly)) { const QByteArray fileData = file.readAll(); + file.close(); RagePhoto ragePhoto; const bool loaded = ragePhoto.load(fileData.data(), static_cast(fileData.size())); if (!loaded) { diff --git a/src/RagePhoto.cpp b/src/RagePhoto.cpp index 0802d44..6fc4178 100644 --- a/src/RagePhoto.cpp +++ b/src/RagePhoto.cpp @@ -27,7 +27,9 @@ #include #endif -#ifdef CODECVT_COMPATIBLE +#if defined WINCVT_COMPATIBLE +#include +#elif defined CODECVT_COMPATIBLE #include #include #elif defined ICONV_COMPATIBLE @@ -85,7 +87,7 @@ bool RagePhoto::load(const char *data, size_t length) m_data.photoFormat = charToUInt32LE(uInt32Buffer); #endif if (m_data.photoFormat == PhotoFormat::GTA5 || m_data.photoFormat == PhotoFormat::RDR2) { -#if defined CODECVT_COMPATIBLE || defined ICONV_COMPATIBLE +#if defined WINCVT_COMPATIBLE || defined CODECVT_COMPATIBLE || defined ICONV_COMPATIBLE char photoHeader[256]; size = readBuffer(data, photoHeader, &pos, 256, length); if (size != 256) { @@ -93,9 +95,21 @@ bool RagePhoto::load(const char *data, size_t length) return false; } -#ifdef CODECVT_COMPATIBLE +#if defined WINCVT_COMPATIBLE + char photoHeader_string[256]; + const int converted = WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(photoHeader), -1, photoHeader_string, 256, NULL, NULL); + if (converted == 0) { + m_data.error = static_cast(Error::UnicodeHeaderError); // 5 + return false; + } + m_data.header = std::string(photoHeader_string); +#elif defined CODECVT_COMPATIBLE std::wstring_convert,char16_t> convert; m_data.header = convert.to_bytes(reinterpret_cast(photoHeader)); + if (convert.converted() == 0) { + m_data.error = static_cast(Error::UnicodeHeaderError); // 5 + return false; + } #elif defined ICONV_COMPATIBLE iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE"); if (iconv_in == (iconv_t)-1) { @@ -465,17 +479,28 @@ const char* RagePhoto::version() bool RagePhoto::save(char *data, uint32_t photoFormat) { if (photoFormat == PhotoFormat::GTA5 || photoFormat == PhotoFormat::RDR2) { -#if defined CODECVT_COMPATIBLE || defined ICONV_COMPATIBLE -#ifdef CODECVT_COMPATIBLE +#if defined WINCVT_COMPATIBLE || defined CODECVT_COMPATIBLE || defined ICONV_COMPATIBLE +#if defined WINCVT_COMPATIBLE + char photoHeader[256]{}; + const int converted = MultiByteToWideChar(CP_UTF8, 0, m_data.header.data(), m_data.header.size(), reinterpret_cast(photoHeader), 256 / sizeof(wchar_t)); + if (converted == 0) { + m_data.error = static_cast(Error::UnicodeHeaderError); // 5 + return false; + } + const size_t photoHeader_size = 256; +#elif defined CODECVT_COMPATIBLE std::wstring_convert,char16_t> convert; std::u16string photoHeader_string = convert.from_bytes(m_data.header); + if (convert.converted() == 0) { + m_data.error = static_cast(Error::UnicodeHeaderError); // 5 + return false; + } const size_t photoHeader_size = photoHeader_string.size() * 2; if (photoHeader_size > 256) { m_data.error = static_cast(Error::HeaderBufferTight); // 34 return false; } - char photoHeader[256]; - memcpy(photoHeader, photoHeader_string.data(), photoHeader_size); + const char *photoHeader = reinterpret_cast(photoHeader_string.data()); #elif defined ICONV_COMPATIBLE iconv_t iconv_in = iconv_open("UTF-16LE", "UTF-8"); if (iconv_in == (iconv_t)-1) { @@ -484,7 +509,7 @@ bool RagePhoto::save(char *data, uint32_t photoFormat) } char photoHeader_string[256]; memcpy(photoHeader_string, m_data.header.data(), m_data.header.size()); - char photoHeader[256]; + char photoHeader[256]{}; size_t src_s = m_data.header.size(); size_t dst_s = sizeof(photoHeader); char *src = photoHeader_string; @@ -495,11 +520,7 @@ bool RagePhoto::save(char *data, uint32_t photoFormat) m_data.error = static_cast(Error::UnicodeHeaderError); // 5 return false; } - const size_t photoHeader_size = m_data.header.size() * 2; - if (photoHeader_size > 256) { - m_data.error = static_cast(Error::HeaderBufferTight); // 34 - return false; - } + const size_t photoHeader_size = 256; #endif if (m_data.photoSize > m_data.photoBuffer) { @@ -614,7 +635,7 @@ bool RagePhoto::save(char *data, uint32_t photoFormat) #endif writeBuffer(uInt32Buffer, data, &pos, length, 4); - writeBuffer(m_data.json.data(), data, &pos, length, jsonString_size); + writeBuffer(m_data.json.c_str(), data, &pos, length, jsonString_size); for (size_t i = jsonString_size; i < m_data.jsonBuffer; i++) { writeBuffer("\0", data, &pos, length, 1); } @@ -629,7 +650,7 @@ bool RagePhoto::save(char *data, uint32_t photoFormat) #endif writeBuffer(uInt32Buffer, data, &pos, length, 4); - writeBuffer(m_data.title.data(), data, &pos, length, titlString_size); + writeBuffer(m_data.title.c_str(), data, &pos, length, titlString_size); for (size_t i = titlString_size; i < m_data.titlBuffer; i++) { writeBuffer("\0", data, &pos, length, 1); } @@ -644,7 +665,7 @@ bool RagePhoto::save(char *data, uint32_t photoFormat) #endif writeBuffer(uInt32Buffer, data, &pos, length, 4); - writeBuffer(m_data.description.data(), data, &pos, length, descString_size); + writeBuffer(m_data.description.c_str(), data, &pos, length, descString_size); for (size_t i = descString_size; i < m_data.descBuffer; i++) { writeBuffer("\0", data, &pos, length, 1); } @@ -708,8 +729,9 @@ bool RagePhoto::saveFile(const std::string &filename, uint32_t photoFormat) return false; } ofs << sdata; + ok = ofs.good(); ofs.close(); - return true; + return ok; } else return false; diff --git a/tests/CodecvtTest.cpp b/tests/CodecvtTest.cpp index f5adce2..bee6052 100644 --- a/tests/CodecvtTest.cpp +++ b/tests/CodecvtTest.cpp @@ -59,5 +59,8 @@ int main(int argc, char *argv[]) }; std::wstring_convert,char16_t> convert; std::string photoString = convert.to_bytes(reinterpret_cast(photoHeader)); + if (convert.converted() == 0) { + return -1; + } return strcmp(photoString.c_str(), "PHOTO - 02/01/17 08:42:44"); } diff --git a/tests/IconvTest.cpp b/tests/IconvTest.cpp index d2d8f52..46b41ab 100644 --- a/tests/IconvTest.cpp +++ b/tests/IconvTest.cpp @@ -56,18 +56,18 @@ int main(int argc, char *argv[]) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - char photoString[256]; + char photoHeader_string[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); + size_t dst_s = sizeof(photoHeader_string); char *src = photoHeader; - char *dst = photoString; + char *dst = photoHeader_string; const size_t ret = iconv(iconv_in, &src, &src_s, &dst, &dst_s); iconv_close(iconv_in); if (ret == static_cast(-1)) { return -1; } - return strcmp(photoString, "PHOTO - 02/01/17 08:42:44"); + return strcmp(photoHeader_string, "PHOTO - 02/01/17 08:42:44"); } diff --git a/tests/WincvtTest.cpp b/tests/WincvtTest.cpp new file mode 100644 index 0000000..e3763f9 --- /dev/null +++ b/tests/WincvtTest.cpp @@ -0,0 +1,64 @@ +/***************************************************************************** +* 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 +#include + +int main(int argc, char *argv[]) +{ + 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 photoHeader_string[256]; + const int converted = WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(photoHeader), -1, photoHeader_string, 256, NULL, NULL); + if (converted == 0) { + return -1; + } + return strcmp(photoHeader_string, "PHOTO - 02/01/17 08:42:44"); +}