Base: Add ASCIIInputStream

Based on the modifications to InputStream from the LinkStage3 fork. Needed for correct restoration of StringHasher.
This commit is contained in:
Chris Hennes
2024-02-17 22:20:53 -06:00
parent 3e47de6d92
commit 44d86f3296
3 changed files with 185 additions and 1 deletions

View File

@@ -621,6 +621,7 @@ void StringHasher::RestoreDocFile(Base::Reader& reader)
void StringHasher::restoreStreamNew(std::istream& stream, std::size_t count)
{
Base::ASCIIInputStream asciiStream (stream);
_hashes->clear();
std::string content;
boost::io::ios_flags_saver ifs(stream);
@@ -688,7 +689,7 @@ void StringHasher::restoreStreamNew(std::istream& stream, std::size_t count)
}
if (!d.isPostfixed()) {
stream >> content;
asciiStream >> content;
if (d.isHashed() || d.isBinary()) {
d._data = QByteArray::fromBase64(content.c_str());
}
@@ -815,7 +816,12 @@ void StringHasher::Restore(Base::XMLReader& reader)
std::size_t count = reader.getAttributeAsUnsigned("count");
if (newTag) {
try {
restoreStreamNew(reader.beginCharStream(), count);
} catch (const Base::Exception &e) {
e.ReportException();
FC_ERR("Failed to restore string table: full-document recompute strongly recommended.");
}
reader.readEndElement("StringHasher2");
return;
}

View File

@@ -832,3 +832,65 @@ std::streambuf::pos_type Streambuf::seekpos(std::streambuf::pos_type pos,
{
return seekoff(pos, std::ios_base::beg);
}
// The custom string handler written by realthunder for the LinkStage3 toponaming code, to handle
// reading multi-line strings directly into a std::string. Imported from LinkStage3 and refactored
// during the TNP mitigation project in February 2024.
ASCIIInputStream& ASCIIInputStream::operator>>(std::string& outputString)
{
uint32_t numberOfLines;
char inputChar;
// The number of lines is followed by a colon as the delimiter. The string itself is then
// allowed to start with any character.
_in >> numberOfLines >> inputChar;
_ss.str("");
for (uint32_t lineNumber = 0; lineNumber < numberOfLines && _in; ++lineNumber) {
while (true) {
if (!_in.get(inputChar)) {
break;
}
// Normalize \r\n to \n
if (inputChar == '\r') {
if (!_in.get(inputChar)) {
break;
}
if (inputChar == '\n') {
break;
}
_ss.put('\r');
_ss.put(inputChar);
}
else {
_ss.put(inputChar);
if (inputChar == '\n') {
break;
}
}
}
}
// Reading the last line
while (_in.get(inputChar)) {
// Normalize \r\n to \n, but DO NOT insert '\n' into the extracted
// line, because the last '\n' is inserted by us (See OutputStream
// operator>>(const char*) above)
if (inputChar == '\r') {
if (!_in.get(inputChar)) {
break;
}
if (inputChar == '\n') {
break;
}
_ss.put('\r');
}
else if (inputChar == '\n') {
break;
}
_ss.put(inputChar);
}
outputString = _ss.str();
return *this;
}

View File

@@ -30,6 +30,7 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "FileInfo.h"
@@ -140,6 +141,121 @@ private:
std::istream& _in;
};
/**
* The ASCIIInputStream class provides reading of ASCII data from an istream, with custom handling
* for std::string to make it easier to read a single multi-line (or multi-word) string. This is
* designed for easy compatibility with the LinkStage3 implementation of the InputStream class, used
* to store StringHashers for the toponaming mitigation technique.
*/
class BaseExport ASCIIInputStream: public Stream
{
public:
/** Constructor
* @param rin: upstream input
*/
explicit ASCIIInputStream(std::istream& rin)
: _in(rin)
{}
ASCIIInputStream(const ASCIIInputStream&) = delete;
ASCIIInputStream(const ASCIIInputStream&&) noexcept = delete;
void operator=(const ASCIIInputStream&) = delete;
void operator=(const ASCIIInputStream&&) = delete;
~ASCIIInputStream() override = default;
ASCIIInputStream& operator>>(bool& input)
{
_in >> input;
return *this;
}
ASCIIInputStream& operator>>(int8_t& ch)
{
int index {};
_in >> index;
ch = (int8_t)index;
return *this;
}
ASCIIInputStream& operator>>(uint8_t& uch)
{
unsigned uns {};
_in >> uns;
uch = (uint8_t)uns;
return *this;
}
ASCIIInputStream& operator>>(int16_t& int16)
{
_in >> int16;
return *this;
}
ASCIIInputStream& operator>>(uint16_t& us)
{
_in >> us;
return *this;
}
ASCIIInputStream& operator>>(int32_t& int32)
{
_in >> int32;
return *this;
}
ASCIIInputStream& operator>>(uint32_t& ui)
{
_in >> ui;
return *this;
}
ASCIIInputStream& operator>>(int64_t& int64)
{
_in >> int64;
return *this;
}
ASCIIInputStream& operator>>(uint64_t& ul)
{
_in >> ul;
return *this;
}
ASCIIInputStream& operator>>(float& flt)
{
_in >> flt;
return *this;
}
ASCIIInputStream& operator>>(double& dbl)
{
_in >> dbl;
return *this;
}
ASCIIInputStream& operator>>(std::string& str);
ASCIIInputStream& operator>>(char& chr)
{
chr = (char)_in.get();
return *this;
}
explicit operator bool() const
{
// test if _Ipfx succeeded
return !_in.eof();
}
private:
std::istream& _in;
std::ostringstream _ss;
};
// ----------------------------------------------------------------------------
/**