1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2023 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// General purpose class to split a multi-line string into lines.
#ifndef OPENVPN_COMMON_SPLITLINES_H
#define OPENVPN_COMMON_SPLITLINES_H
#include <utility>
#include <openvpn/common/string.hpp>
namespace openvpn {
template <typename STRING>
class SplitLinesType
{
public:
OPENVPN_EXCEPTION(overflow_error);
OPENVPN_EXCEPTION(moved_error);
/**
* Initialises SplitLinesType object with pointer to str
*
* Note: string/buffer passed to constructor is not locally stored,
* so it must remain in scope and not be modified during the lifetime
* of the SplitLines object.
*
* @param max_line_len_arg If not 0, specifies line length that
* will trigger overflow error.
*/
SplitLinesType(const STRING &str, const size_t max_line_len_arg = 0)
: data((const char *)str.c_str()),
size(str.length()),
max_line_len(max_line_len_arg)
{
}
/**
* Read next line so that it can be accessed with line_ref or line_move.
*
* If max_line_len is greater zero, read at most max_line_len characters.
*
* @param trim If true, remove trailing \n or \r\n
* @return Returns true if any characters were read.
*/
bool operator()(const bool trim = true)
{
line.clear();
overflow = false;
line_valid = true;
const size_t overflow_index = index + max_line_len;
while (index < size)
{
if (max_line_len && index >= overflow_index)
{
overflow = true;
return true;
}
const char c = data[index++];
line += c;
if (c == '\n' || index >= size)
{
if (trim)
string::trim_crlf(line);
return true;
}
}
line_valid = false;
return false;
}
/**
* Returns true if max_line_len is greater zero and the current line was
* longer than max_line_len characters.
*/
bool line_overflow() const
{
return overflow;
}
/**
* Returns reference to current line.
*
* Throws an exception if there is no line available currently.
* Throws an exception if line_overflow() returns true.
*/
std::string &line_ref()
{
validate();
return line;
}
/**
* Returns const reference to current line.
*
* Throws an exception if there is no line available currently.
* Throws an exception if line_overflow() returns true.
*/
const std::string &line_ref() const
{
validate();
return line;
}
/**
* Returns the moved current line.
*
* Throws an exception if there is no line available currently.
* Throws an exception if line_overflow() returns true.
* Further calls to line_ref() or line_moved() will throw an exception until
* operator() is called again.
*/
std::string line_move()
{
validate();
line_valid = false;
return std::move(line);
}
enum Status
{
S_OKAY, //!< next line was successfully read
S_EOF, //!< no further characters are available
S_ERROR //!< line was longer than allowed
};
/**
* Read the next line and move it into ln.
*
* Does not throw an exception on overflow but instead
* returns S_ERROR. If nothing could be read, returns
* S_EOF.
* Since the line is moved into the argument, you can't
* use line_ref() or line_moved() on the object afterwards.
* In general calls to operator()+line_ref() and next()
* are not intended to be mixed.
*
* @param ln string to move the line into.
* @param trim If true, remove trailing \n or \r\n
* @return Returns S_OKAY if a line was moved into ln.
*/
Status next(std::string &ln, const bool trim = true)
{
const bool s = (*this)(trim);
if (!s)
return S_EOF;
if (overflow)
return S_ERROR;
ln = std::move(line);
line_valid = false;
return S_OKAY;
}
private:
void validate()
{
if (!line_valid)
throw moved_error();
if (overflow)
throw overflow_error(line);
}
const char *data;
size_t size;
const size_t max_line_len;
size_t index = 0;
std::string line;
bool line_valid = false;
bool overflow = false;
};
typedef SplitLinesType<std::string> SplitLines;
} // namespace openvpn
#endif
|