summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsdserialize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llsdserialize.cpp')
-rw-r--r--indra/llcommon/llsdserialize.cpp125
1 files changed, 69 insertions, 56 deletions
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 046523dbb1..e7482b601d 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -34,6 +34,9 @@
#include <iostream>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
#ifdef LL_USESYSTEMLIBS
# include <zlib.h>
#else
@@ -2177,7 +2180,9 @@ std::string zip_llsd(LLSD& data)
{ //copy result into output
if (strm.avail_out >= CHUNK)
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2200,7 +2205,9 @@ std::string zip_llsd(LLSD& data)
}
else
{
- free(output);
+ deflateEnd(&strm);
+ if(output)
+ free(output);
LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
return std::string();
}
@@ -2211,7 +2218,8 @@ std::string zip_llsd(LLSD& data)
std::string result((char*) output, size);
deflateEnd(&strm);
- free(output);
+ if(output)
+ free(output);
return result;
}
@@ -2221,53 +2229,66 @@ std::string zip_llsd(LLSD& data)
// and deserializes from that copy using LLSDSerialize
LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)
{
+ std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]);
+ if (!in)
+ {
+ return ZR_MEM_ERROR;
+ }
+ is.read((char*) in.get(), size);
+
+ return unzip_llsd(data, in.get(), size);
+}
+
+LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size)
+{
U8* result = NULL;
- llssize cur_size = 0;
+ U32 cur_size = 0;
z_stream strm;
- const U32 CHUNK = 65536;
+ constexpr U32 CHUNK = 1024 * 512;
- U8 *in = new(std::nothrow) U8[size];
- if (!in)
+ static thread_local std::unique_ptr<U8[]> out;
+ if (!out)
{
- return ZR_MEM_ERROR;
+ out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]);
}
- is.read((char*) in, size);
-
- U8 out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = size;
- strm.next_in = in;
+ strm.next_in = const_cast<U8*>(in);
S32 ret = inflateInit(&strm);
do
{
strm.avail_out = CHUNK;
- strm.next_out = out;
+ strm.next_out = out.get();
ret = inflate(&strm, Z_NO_FLUSH);
- if (ret == Z_STREAM_ERROR)
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
{
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_DATA_ERROR;
}
-
- switch (ret)
+ case Z_STREAM_ERROR:
+ case Z_BUF_ERROR:
{
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- case Z_DATA_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ return ZR_BUFFER_ERROR;
+ }
+
case Z_MEM_ERROR:
+ {
inflateEnd(&strm);
free(result);
- delete [] in;
return ZR_MEM_ERROR;
- break;
+ }
}
U32 have = CHUNK-strm.avail_out;
@@ -2280,17 +2301,15 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
{
free(result);
}
- delete[] in;
return ZR_MEM_ERROR;
}
result = new_result;
- memcpy(result+cur_size, out, have);
+ memcpy(result+cur_size, out.get(), have);
cur_size += have;
- } while (ret == Z_OK);
+ } while (ret == Z_OK && ret != Z_STREAM_END);
inflateEnd(&strm);
- delete [] in;
if (ret != Z_STREAM_END)
{
@@ -2300,37 +2319,11 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
//result now points to the decompressed LLSD block
{
- std::istringstream istr;
- // Since we are using this for meshes, data we are dealing with tend to be large.
- // So string can potentially fail to allocate, make sure this won't cause problems
- try
- {
- std::string res_str((char*)result, cur_size);
-
- std::string deprecated_header("<? LLSD/Binary ?>");
-
- if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
- {
- res_str = res_str.substr(deprecated_header.size() + 1, cur_size);
- }
- cur_size = res_str.size();
-
- istr.str(res_str);
- }
-#ifdef LL_WINDOWS
- catch (std::length_error)
- {
- free(result);
- return ZR_SIZE_ERROR;
- }
-#endif
- catch (std::bad_alloc&)
- {
- free(result);
- return ZR_MEM_ERROR;
- }
+ char* result_ptr = strip_deprecated_header((char*)result, cur_size);
- if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH))
+ boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size);
+
+ if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))
{
free(result);
return ZR_PARSE_ERROR;
@@ -2443,3 +2436,23 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size
return result;
}
+
+char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
+{
+ const char* deprecated_header = "<? LLSD/Binary ?>";
+ constexpr size_t deprecated_header_size = 17;
+
+ if (cur_size > deprecated_header_size
+ && memcmp(in, deprecated_header, deprecated_header_size) == 0)
+ {
+ in = in + deprecated_header_size;
+ cur_size = cur_size - deprecated_header_size;
+ if (header_size)
+ {
+ *header_size = deprecated_header_size + 1;
+ }
+ }
+
+ return in;
+}
+