add save feature

This commit is contained in:
Syping 2021-09-17 07:22:49 +02:00
parent 84b5937c95
commit 5bdbb09c7a
2 changed files with 258 additions and 8 deletions

View File

@ -94,7 +94,7 @@ bool RagePhoto::load(const char *data, size_t length)
}
#ifdef CODECVT_COMPATIBLE
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t, 0x10ffff, std::little_endian>,char16_t> convert;
p_photoString = convert.to_bytes(reinterpret_cast<char16_t*>(photoHeader));
#elif defined ICONV_COMPATIBLE
iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
@ -114,6 +114,10 @@ bool RagePhoto::load(const char *data, size_t length)
return false;
}
p_photoString = std::string(photoString);
#else
std::cout << "UTF-16LE decoding support missing" << std::endl;
p_error = Error::UnicodeInitError; // 4
return false;
#endif
size = readBuffer(data, uInt32Buffer, &pos, 4, length);
@ -410,7 +414,7 @@ uint32_t RagePhoto::photoSize()
if (p_photoLoaded)
return p_photoSize;
else
return 0;
return 0UL;
}
const std::string RagePhoto::description()
@ -433,17 +437,226 @@ const std::string RagePhoto::title()
return p_titleString;
}
uint32_t RagePhoto::saveSize(PhotoFormat photoFormat)
bool RagePhoto::save(char *data, PhotoFormat photoFormat)
{
if (photoFormat == PhotoFormat::GTA5 || photoFormat == PhotoFormat::RDR2) {
#ifdef CODECVT_COMPATIBLE
std::wstring_convert<std::codecvt_utf8_utf16<char16_t, 0x10ffff, std::little_endian>,char16_t> convert;
std::u16string photoString = convert.from_bytes(p_photoString);
uint32_t photoString_size = photoString.size() * 2 + 1;
if (photoString_size > 256) {
p_error = Error::HeaderBufferTight; // 34
return false;
}
char photoHeader[256];
memcpy(photoHeader, photoString.data(), photoString_size);
#else
std::cout << "UTF-16LE encoding support missing" << std::endl;
p_error = Error::UnicodeInitError; // 4
return false;
#endif
if (p_photoSize > p_photoBuffer) {
p_error = Error::PhotoBufferTight; // 35
return false;
}
uint32_t jsonString_size = p_jsonString.size() + 1;
if (jsonString_size > p_jsonBuffer) {
p_error = Error::JsonBufferTight; // 36
return false;
}
uint32_t titlString_size = p_titleString.size() + 1;
if (titlString_size > p_titlBuffer) {
p_error = Error::TitleBufferTight; // 37
return false;
}
uint32_t descString_size = p_descriptionString.size() + 1;
if (descString_size > p_descBuffer) {
p_error = Error::DescBufferTight; // 38
return false;
}
size_t length = saveSize(photoFormat);
size_t pos = 0;
char uInt32Buffer[4];
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &photoFormat, 4);
#else
uInt32ToCharLE(static_cast<uint32_t>(photoFormat), uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer(photoHeader, data, &pos, length, photoString_size);
for (size_t i = photoString_size; i < 256; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_headerSum, 4);
#else
uInt32ToCharLE(p_headerSum, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
if (photoFormat == PhotoFormat::RDR2) {
for (size_t i = 0; i < 8; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
}
uint32_t headerSize = pos;
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_endOfFile, 4);
#else
uInt32ToCharLE(p_endOfFile, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_jsonOffset, 4);
#else
uInt32ToCharLE(p_jsonOffset, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_titlOffset, 4);
#else
uInt32ToCharLE(p_titlOffset, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_descOffset, 4);
#else
uInt32ToCharLE(p_descOffset, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer("JPEG", data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_photoBuffer, 4);
#else
uInt32ToCharLE(p_photoBuffer, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_photoSize, 4);
#else
uInt32ToCharLE(p_photoSize, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer(p_photoData, data, &pos, length, p_photoSize);
for (size_t i = p_photoSize; i < p_photoBuffer; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
pos = p_jsonOffset + headerSize;
writeBuffer("JSON", data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_jsonBuffer, 4);
#else
uInt32ToCharLE(p_jsonBuffer, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer(p_jsonString.data(), data, &pos, length, jsonString_size);
for (size_t i = jsonString_size; i < p_jsonBuffer; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
pos = p_titlOffset + headerSize;
writeBuffer("TITL", data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_titlBuffer, 4);
#else
uInt32ToCharLE(p_titlBuffer, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer(p_titleString.data(), data, &pos, length, titlString_size);
for (size_t i = titlString_size; i < p_titlBuffer; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
pos = p_descOffset + headerSize;
writeBuffer("DESC", data, &pos, length, 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(uInt32Buffer, &p_descBuffer, 4);
#else
uInt32ToCharLE(p_descBuffer, uInt32Buffer);
#endif
writeBuffer(uInt32Buffer, data, &pos, length, 4);
writeBuffer(p_descriptionString.data(), data, &pos, length, descString_size);
for (size_t i = descString_size; i < p_descBuffer; i++) {
writeBuffer("\0", data, &pos, length, 1);
}
pos = p_endOfFile + headerSize - 4;
writeBuffer("JEND", data, &pos, length, 4);
p_error = Error::NoError; // 255
return true;
}
p_error = Error::IncompatibleFormat; // 2
return false;
}
bool RagePhoto::save(char *data)
{
return save(data, p_photoFormat);
}
const std::string RagePhoto::save(PhotoFormat photoFormat, bool *ok)
{
size_t size = saveSize(photoFormat);
if (size == 0) {
if (ok)
*ok = false;
return std::string();
}
char *data = static_cast<char*>(malloc(size));
if (!data) {
if (ok)
*ok = false;
return std::string();
}
const bool saved = save(data, photoFormat);
if (ok)
*ok = saved;
const std::string sdata = std::string(data, size);
free(data);
return sdata;
}
const std::string RagePhoto::save(bool *ok)
{
return save(p_photoFormat, ok);
}
size_t RagePhoto::saveSize(PhotoFormat photoFormat)
{
if (photoFormat == PhotoFormat::GTA5)
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + GTA5_HEADERSIZE + 56UL);
else if (photoFormat == PhotoFormat::RDR2)
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + RDR2_HEADERSIZE + 56UL);
else
return 0UL;
return 0;
}
uint32_t RagePhoto::saveSize()
size_t RagePhoto::saveSize()
{
return saveSize(p_photoFormat);
}
@ -556,7 +769,7 @@ size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_
{
size_t readLen = 0;
if (*pos >= inputLen)
return readLen;
return 0;
readLen = inputLen - *pos;
if (readLen > len)
readLen = len;
@ -565,6 +778,19 @@ size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_
return readLen;
}
size_t RagePhoto::writeBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen)
{
const size_t maxLen = len - *pos;
size_t writeLen = inputLen;
if (*pos >= len)
return 0;
if (inputLen > maxLen)
writeLen = maxLen;
memcpy(&output[*pos], input, writeLen);
*pos = *pos + writeLen;
return writeLen;
}
uint32_t RagePhoto::charToUInt32LE(char *x)
{
return (static_cast<unsigned char>(x[3]) << 24 |

View File

@ -37,8 +37,10 @@ class LIBRAGEPHOTO_EXPORT RagePhoto
public:
/** Parsing and set errors */
enum class Error : uint8_t {
DescBufferTight = 38, /**< Description Buffer is too tight */
DescMallocError = 30, /**< Description Buffer can't be allocated */
DescReadError = 31, /**< Description can't be read successfully */
HeaderBufferTight = 34, /**< Header Buffer is too tight */
IncompatibleFormat = 2, /**< Format is incompatible */
IncompleteChecksum = 6, /**< Header checksum is incomplete */
IncompleteDescBuffer = 29, /**< Description Buffer Size is incomplete */
@ -61,12 +63,15 @@ public:
IncorrectJpegMarker = 12, /**< JPEG Marker is incorrect */
IncorrectJsonMarker = 18, /**< JSON Marker is incorrect */
IncorrectTitleMarker = 23, /**< Title Marker is incorrect */
JsonBufferTight = 36, /**< JSON Buffer is too tight */
JsonMallocError = 20, /**< JSON Buffer can't be allocated */
JsonReadError = 21, /**< JSON can't be read successfully */
NoError = 255, /**< Finished without errors */
NoFormatIdentifier = 1, /**< No format detected, empty file */
PhotoBufferTight = 35, /**< Photo Buffer is too tight */
PhotoMallocError = 15, /**< Photo Buffer can't be allocated */
PhotoReadError = 16, /**< Photo can't be read */
TitleBufferTight = 37, /**< Title Buffer is too tight */
TitleMallocError = 25, /**< Title Buffer can't be allocated */
TitleReadError = 26, /**< Title can't be read */
UnicodeHeaderError = 5, /**< Header can't be decoded */
@ -100,8 +105,26 @@ public:
const std::string json(); /**< Returns the Photo JSON data. */
const std::string header(); /**< Returns the Photo header. */
const std::string title(); /**< Returns the Photo title. */
uint32_t saveSize(PhotoFormat photoFormat); /**< Returns the save file size. */
uint32_t saveSize(); /**< Returns the save file size. */
/** Saves a Photo to a char*.
* \param data Photo data
* \param photoFormat Photo Format (GTA V or RDR 2)
*/
bool save(char *data, PhotoFormat photoFormat);
/** Saves a Photo to a char*.
* \param data Photo data
*/
bool save(char *data);
/** Saves a Photo to a std::string.
* \param photoFormat Photo Format (GTA V or RDR 2)
* \param ok \p true when saved successfully
*/
const std::string save(PhotoFormat photoFormat, bool *ok = nullptr);
/** Saves a Photo to a std::string.
* \param ok \p true when saved successfully
*/
const std::string save(bool *ok = nullptr);
size_t saveSize(PhotoFormat photoFormat); /**< Returns the save file size. */
size_t saveSize(); /**< Returns the save file size. */
void setBufferDefault(); /**< Sets all cross-format Buffer to default size. */
void setDescription(const std::string &description, uint32_t bufferSize = 0); /**< Sets the Photo description. */
void setFormat(PhotoFormat photoFormat); /**< Sets the Photo Format (GTA V or RDR 2). */
@ -123,6 +146,7 @@ public:
protected:
inline void moveOffsets();
inline size_t readBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen);
inline size_t writeBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen);
inline uint32_t charToUInt32LE(char *x);
inline void uInt32ToCharLE(uint32_t x, char *y);
bool p_photoLoaded;