add save feature
This commit is contained in:
parent
84b5937c95
commit
5bdbb09c7a
2 changed files with 258 additions and 8 deletions
|
@ -94,7 +94,7 @@ bool RagePhoto::load(const char *data, size_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CODECVT_COMPATIBLE
|
#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));
|
p_photoString = convert.to_bytes(reinterpret_cast<char16_t*>(photoHeader));
|
||||||
#elif defined ICONV_COMPATIBLE
|
#elif defined ICONV_COMPATIBLE
|
||||||
iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
p_photoString = std::string(photoString);
|
p_photoString = std::string(photoString);
|
||||||
|
#else
|
||||||
|
std::cout << "UTF-16LE decoding support missing" << std::endl;
|
||||||
|
p_error = Error::UnicodeInitError; // 4
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size = readBuffer(data, uInt32Buffer, &pos, 4, length);
|
size = readBuffer(data, uInt32Buffer, &pos, 4, length);
|
||||||
|
@ -410,7 +414,7 @@ uint32_t RagePhoto::photoSize()
|
||||||
if (p_photoLoaded)
|
if (p_photoLoaded)
|
||||||
return p_photoSize;
|
return p_photoSize;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string RagePhoto::description()
|
const std::string RagePhoto::description()
|
||||||
|
@ -433,17 +437,226 @@ const std::string RagePhoto::title()
|
||||||
return p_titleString;
|
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)
|
if (photoFormat == PhotoFormat::GTA5)
|
||||||
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + GTA5_HEADERSIZE + 56UL);
|
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + GTA5_HEADERSIZE + 56UL);
|
||||||
else if (photoFormat == PhotoFormat::RDR2)
|
else if (photoFormat == PhotoFormat::RDR2)
|
||||||
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + RDR2_HEADERSIZE + 56UL);
|
return (p_photoBuffer + p_jsonBuffer + p_titlBuffer + p_descBuffer + RDR2_HEADERSIZE + 56UL);
|
||||||
else
|
else
|
||||||
return 0UL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RagePhoto::saveSize()
|
size_t RagePhoto::saveSize()
|
||||||
{
|
{
|
||||||
return saveSize(p_photoFormat);
|
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;
|
size_t readLen = 0;
|
||||||
if (*pos >= inputLen)
|
if (*pos >= inputLen)
|
||||||
return readLen;
|
return 0;
|
||||||
readLen = inputLen - *pos;
|
readLen = inputLen - *pos;
|
||||||
if (readLen > len)
|
if (readLen > len)
|
||||||
readLen = len;
|
readLen = len;
|
||||||
|
@ -565,6 +778,19 @@ size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_
|
||||||
return readLen;
|
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)
|
uint32_t RagePhoto::charToUInt32LE(char *x)
|
||||||
{
|
{
|
||||||
return (static_cast<unsigned char>(x[3]) << 24 |
|
return (static_cast<unsigned char>(x[3]) << 24 |
|
||||||
|
|
|
@ -37,8 +37,10 @@ class LIBRAGEPHOTO_EXPORT RagePhoto
|
||||||
public:
|
public:
|
||||||
/** Parsing and set errors */
|
/** Parsing and set errors */
|
||||||
enum class Error : uint8_t {
|
enum class Error : uint8_t {
|
||||||
|
DescBufferTight = 38, /**< Description Buffer is too tight */
|
||||||
DescMallocError = 30, /**< Description Buffer can't be allocated */
|
DescMallocError = 30, /**< Description Buffer can't be allocated */
|
||||||
DescReadError = 31, /**< Description can't be read successfully */
|
DescReadError = 31, /**< Description can't be read successfully */
|
||||||
|
HeaderBufferTight = 34, /**< Header Buffer is too tight */
|
||||||
IncompatibleFormat = 2, /**< Format is incompatible */
|
IncompatibleFormat = 2, /**< Format is incompatible */
|
||||||
IncompleteChecksum = 6, /**< Header checksum is incomplete */
|
IncompleteChecksum = 6, /**< Header checksum is incomplete */
|
||||||
IncompleteDescBuffer = 29, /**< Description Buffer Size is incomplete */
|
IncompleteDescBuffer = 29, /**< Description Buffer Size is incomplete */
|
||||||
|
@ -61,12 +63,15 @@ public:
|
||||||
IncorrectJpegMarker = 12, /**< JPEG Marker is incorrect */
|
IncorrectJpegMarker = 12, /**< JPEG Marker is incorrect */
|
||||||
IncorrectJsonMarker = 18, /**< JSON Marker is incorrect */
|
IncorrectJsonMarker = 18, /**< JSON Marker is incorrect */
|
||||||
IncorrectTitleMarker = 23, /**< Title Marker is incorrect */
|
IncorrectTitleMarker = 23, /**< Title Marker is incorrect */
|
||||||
|
JsonBufferTight = 36, /**< JSON Buffer is too tight */
|
||||||
JsonMallocError = 20, /**< JSON Buffer can't be allocated */
|
JsonMallocError = 20, /**< JSON Buffer can't be allocated */
|
||||||
JsonReadError = 21, /**< JSON can't be read successfully */
|
JsonReadError = 21, /**< JSON can't be read successfully */
|
||||||
NoError = 255, /**< Finished without errors */
|
NoError = 255, /**< Finished without errors */
|
||||||
NoFormatIdentifier = 1, /**< No format detected, empty file */
|
NoFormatIdentifier = 1, /**< No format detected, empty file */
|
||||||
|
PhotoBufferTight = 35, /**< Photo Buffer is too tight */
|
||||||
PhotoMallocError = 15, /**< Photo Buffer can't be allocated */
|
PhotoMallocError = 15, /**< Photo Buffer can't be allocated */
|
||||||
PhotoReadError = 16, /**< Photo can't be read */
|
PhotoReadError = 16, /**< Photo can't be read */
|
||||||
|
TitleBufferTight = 37, /**< Title Buffer is too tight */
|
||||||
TitleMallocError = 25, /**< Title Buffer can't be allocated */
|
TitleMallocError = 25, /**< Title Buffer can't be allocated */
|
||||||
TitleReadError = 26, /**< Title can't be read */
|
TitleReadError = 26, /**< Title can't be read */
|
||||||
UnicodeHeaderError = 5, /**< Header can't be decoded */
|
UnicodeHeaderError = 5, /**< Header can't be decoded */
|
||||||
|
@ -100,8 +105,26 @@ public:
|
||||||
const std::string json(); /**< Returns the Photo JSON data. */
|
const std::string json(); /**< Returns the Photo JSON data. */
|
||||||
const std::string header(); /**< Returns the Photo header. */
|
const std::string header(); /**< Returns the Photo header. */
|
||||||
const std::string title(); /**< Returns the Photo title. */
|
const std::string title(); /**< Returns the Photo title. */
|
||||||
uint32_t saveSize(PhotoFormat photoFormat); /**< Returns the save file size. */
|
/** Saves a Photo to a char*.
|
||||||
uint32_t saveSize(); /**< Returns the save file size. */
|
* \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 setBufferDefault(); /**< Sets all cross-format Buffer to default size. */
|
||||||
void setDescription(const std::string &description, uint32_t bufferSize = 0); /**< Sets the Photo description. */
|
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). */
|
void setFormat(PhotoFormat photoFormat); /**< Sets the Photo Format (GTA V or RDR 2). */
|
||||||
|
@ -123,6 +146,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
inline void moveOffsets();
|
inline void moveOffsets();
|
||||||
inline size_t readBuffer(const char *input, char *output, size_t *pos, size_t len, size_t inputLen);
|
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 uint32_t charToUInt32LE(char *x);
|
||||||
inline void uInt32ToCharLE(uint32_t x, char *y);
|
inline void uInt32ToCharLE(uint32_t x, char *y);
|
||||||
bool p_photoLoaded;
|
bool p_photoLoaded;
|
||||||
|
|
Loading…
Reference in a new issue