diff --git a/io/binaryreader.cpp b/io/binaryreader.cpp index e4d77bf..7d12006 100644 --- a/io/binaryreader.cpp +++ b/io/binaryreader.cpp @@ -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(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)); } /*! diff --git a/io/binarywriter.cpp b/io/binarywriter.cpp index dd9e5b7..277c7d0 100644 --- a/io/binarywriter.cpp +++ b/io/binarywriter.cpp @@ -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(0x4000 | length), m_buffer); - m_stream->write(m_buffer, 2); - } else if (length < 0x200000) { - BE::getBytes(static_cast(0x200000 | length), m_buffer); - m_stream->write(m_buffer + 1, 3); - } else if (length < 0x10000000) { - BE::getBytes(static_cast(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(size)); } diff --git a/testfiles/some_data b/testfiles/some_data index 3dfd5a7..0e85b07 100644 Binary files a/testfiles/some_data and b/testfiles/some_data differ diff --git a/tests/iotests.cpp b/tests/iotests.cpp index e0523d9..11f2a7e 100644 --- a/tests/iotests.cpp +++ b/tests/iotests.cpp @@ -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(95)); + CPPUNIT_ASSERT_EQUAL(reader.readStreamsize(), static_cast(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