binary reader/writer: Increase limit of length-prefixed strings

So strings with a size up to 0xFFFFFFFFFFFFFF byte can be handled.
This commit is contained in:
Martchus 2017-07-28 20:34:50 +02:00
parent f4faf652fd
commit 1d4a4bd2be
4 changed files with 28 additions and 20 deletions

View File

@ -100,7 +100,7 @@ istream::pos_type BinaryReader::readStreamsize()
*/
string BinaryReader::readLengthPrefixedString()
{
static const int maxPrefixLength = 4;
static constexpr int maxPrefixLength = 8;
int prefixLength = 1;
const byte beg = static_cast<byte>(m_stream->peek());
byte mask = 0x80;
@ -114,8 +114,7 @@ string BinaryReader::readLengthPrefixedString()
memset(m_buffer, 0, maxPrefixLength);
m_stream->read(m_buffer + (maxPrefixLength - prefixLength), prefixLength);
*(m_buffer + (maxPrefixLength - prefixLength)) ^= mask;
uint32 prefix = BE::toUInt32(m_buffer);
return readString(prefix);
return readString(BE::toUInt64(m_buffer));
}
/*!

View File

@ -77,21 +77,18 @@ void BinaryWriter::setStream(ostream *stream, bool giveOwnership)
*/
void BinaryWriter::writeLengthPrefixedString(const string &value)
{
size_t length = value.length();
if (length < 0x80) {
m_buffer[0] = 0x80 | length;
m_stream->write(m_buffer, 1);
} else if (length < 0x4000) {
BE::getBytes(static_cast<uint16>(0x4000 | length), m_buffer);
m_stream->write(m_buffer, 2);
} else if (length < 0x200000) {
BE::getBytes(static_cast<uint32>(0x200000 | length), m_buffer);
m_stream->write(m_buffer + 1, 3);
} else if (length < 0x10000000) {
BE::getBytes(static_cast<uint32>(0x10000000 | length), m_buffer);
m_stream->write(m_buffer, 4);
} else {
const uint64 size = value.size();
uint64 boundCheck = 0x80;
byte prefixLength = 1;
for (; boundCheck != 0x8000000000000000; boundCheck <<= 7, ++prefixLength) {
if (size < boundCheck) {
BE::getBytes(size | boundCheck, m_buffer);
break;
}
}
if (prefixLength == 9) {
throw ConversionException("The size of the string exceeds the maximum.");
}
m_stream->write(value.c_str(), length);
m_stream->write(m_buffer + 8 - prefixLength, prefixLength);
m_stream->write(value.data(), static_cast<streamsize>(size));
}

Binary file not shown.

View File

@ -1,5 +1,6 @@
#include "./testutils.h"
#include "../conversion/conversionexception.h"
#include "../io/binaryreader.h"
#include "../io/binarywriter.h"
#include "../io/bitreader.h"
@ -20,6 +21,7 @@ using namespace std;
using namespace IoUtilities;
using namespace TestUtilities;
using namespace TestUtilities::Literals;
using namespace ConversionUtilities;
using namespace CPPUNIT_NS;
@ -98,7 +100,7 @@ void IoTests::testBinaryReader()
testFile.exceptions(ios_base::failbit | ios_base::badbit);
testFile.open(TestUtilities::testFilePath("some_data"), ios_base::in | ios_base::binary);
BinaryReader reader(&testFile);
CPPUNIT_ASSERT_EQUAL(reader.readStreamsize(), static_cast<istream::pos_type>(95));
CPPUNIT_ASSERT_EQUAL(reader.readStreamsize(), static_cast<istream::pos_type>(398));
CPPUNIT_ASSERT(reader.readUInt16LE() == 0x0102u);
CPPUNIT_ASSERT(reader.readUInt16BE() == 0x0102u);
CPPUNIT_ASSERT(reader.readUInt24LE() == 0x010203u);
@ -132,7 +134,14 @@ void IoTests::testBinaryReader()
CPPUNIT_ASSERT(reader.readBool() == true);
CPPUNIT_ASSERT(reader.readString(3) == "abc");
CPPUNIT_ASSERT(reader.readLengthPrefixedString() == "ABC");
CPPUNIT_ASSERT(reader.readLengthPrefixedString() == "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
"23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123"
"45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"
"678901234567890123456789");
CPPUNIT_ASSERT(reader.readTerminatedString() == "def");
CPPUNIT_ASSERT_THROW(reader.readLengthPrefixedString(), ConversionException);
CPPUNIT_ASSERT_MESSAGE("pos in stream not advanced on conversion error", reader.readByte() == 0);
// test ownership
reader.setStream(nullptr, true);
reader.setStream(new fstream(), true);
@ -156,7 +165,7 @@ void IoTests::testBinaryWriter()
// prepare output stream
stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
outputStream.exceptions(ios_base::failbit | ios_base::badbit);
char testData[95];
char testData[397];
outputStream.rdbuf()->pubsetbuf(testData, sizeof(testData));
// write test data
@ -205,6 +214,9 @@ void IoTests::testBinaryWriter()
writer.writeBool(true);
writer.writeString("abc");
writer.writeLengthPrefixedString("ABC");
writer.writeLengthPrefixedString("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
"234567890123456789012345678901234567890123456789012345678901234567890123456789");
writer.writeTerminatedString("def");
// test written values