diff --git a/include/qpdf/InputSource.hh b/include/qpdf/InputSource.hh index 889ce69..0ece2bb 100644 --- a/include/qpdf/InputSource.hh +++ b/include/qpdf/InputSource.hh @@ -78,6 +78,8 @@ class QPDF_DLL_CLASS InputSource // The following methods are for internal use by qpdf only. inline size_t read(std::string& str, size_t count, qpdf_offset_t at = -1); inline std::string read(size_t count, qpdf_offset_t at = -1); + size_t read_line(std::string& str, size_t count, qpdf_offset_t at = -1); + std::string read_line(size_t count, qpdf_offset_t at = -1); inline qpdf_offset_t fastTell(); inline bool fastRead(char&); inline void fastUnread(bool); diff --git a/libqpdf/InputSource.cc b/libqpdf/InputSource.cc index b9ee128..1530ed4 100644 --- a/libqpdf/InputSource.cc +++ b/libqpdf/InputSource.cc @@ -5,6 +5,8 @@ #include #include +using namespace std::literals; + void InputSource::setLastOffset(qpdf_offset_t offset) { @@ -17,27 +19,42 @@ InputSource::getLastOffset() const return this->last_offset; } -std::string -InputSource::readLine(size_t max_line_length) +size_t +InputSource::read_line(std::string& str, size_t count, qpdf_offset_t at) { // Return at most max_line_length characters from the next line. Lines are terminated by one or // more \r or \n characters. Consume the trailing newline characters but don't return them. // After this is called, the file will be positioned after a line terminator or at the end of // the file, and last_offset will point to position the file had when this method was called. - qpdf_offset_t offset = this->tell(); - auto bp = std::make_unique(max_line_length + 1); - char* buf = bp.get(); - memset(buf, '\0', max_line_length + 1); - this->read(buf, max_line_length); - this->seek(offset, SEEK_SET); - qpdf_offset_t eol = this->findAndSkipNextEOL(); - this->last_offset = offset; - size_t line_length = QIntC::to_size(eol - offset); - if (line_length < max_line_length) { - buf[line_length] = '\0'; + read(str, count, at); + auto eol = str.find_first_of("\n\r"sv); + if (eol != std::string::npos) { + auto next_line = str.find_first_not_of("\n\r"sv, eol); + str.resize(eol); + if (eol != std::string::npos) { + seek(last_offset + static_cast(next_line), SEEK_SET); + return eol; + } } - return {buf}; + // We did not necessarily find the end of the trailing newline sequence. + seek(last_offset, SEEK_SET); + findAndSkipNextEOL(); + return eol; +} + +std::string +InputSource::readLine(size_t max_line_length) +{ + return read_line(max_line_length); +} + +inline std::string +InputSource::read_line(size_t count, qpdf_offset_t at) +{ + std::string result(count, '\0'); + read_line(result, count, at); + return result; } bool