20 : separator_(1, separator), values_(cols) {
24 : separator_(1, separator) {
39 while (prev_pos < line.size()) {
41 sep_pos = line.find_first_of(separator_, prev_pos);
42 if (sep_pos == std::string::npos) {
47 len = sep_pos - prev_pos;
48 values_.push_back(line.substr(prev_pos, len));
51 prev_pos = sep_pos + 1;
55 len = line.size() - prev_pos;
56 values_.push_back(line.substr(prev_pos, len));
73 for (
size_t i = 0; i < values_.size(); ++i) {
97 values_.resize(values_.size() - count);
106CSVRow::checkIndex(
const size_t at)
const {
107 if (at >= values_.size()) {
108 isc_throw(CSVFileError,
"value index '" << at <<
"' of the CSV row"
109 " is out of bounds; maximal index is '"
110 << (values_.size() - 1) <<
"'");
115 : filename_(filename), fs_(), cols_(0), read_msg_() {
134 std::ifstream fs(filename_.c_str());
135 const bool file_exists = fs.good();
137 return (file_exists);
142 checkStreamStatusAndReset(
"flush");
159 if (std::find(cols_.begin(), cols_.end(), col_name) != cols_.end()) {
163 cols_.push_back(col_name);
168 checkStreamStatusAndReset(
"append");
184 fs_->seekp(0, std::ios_base::end);
185 fs_->seekg(0, std::ios_base::end);
188 std::string text = row.
render();
189 *fs_ << text << std::endl;
190 auto sav_err = errno;
192 std::stringstream ss;
193 ss <<
"failed to write CSV row '"
194 << text <<
"' to the file '" << filename_ <<
"'"
195 <<
" fail(): " << fs_->fail()
196 <<
" bad(): " << fs_->bad()
197 <<
" errno: " << sav_err
198 <<
" reason: " << strerror(sav_err);
199 auto error_str = ss.str();
212CSVFile::checkStreamStatusAndReset(
const std::string& operation)
const {
215 << operation <<
"' on file '" << filename_ <<
"'");
217 }
else if (!fs_->is_open()) {
219 isc_throw(CSVFileError,
"closed stream when performing '"
220 << operation <<
"' on file '" << filename_ <<
"'");
228CSVFile::size()
const {
229 std::ifstream fs(filename_.c_str());
237 std::ifstream::pos_type pos;
241 fs.seekg(0, std::ifstream::end);
244 }
catch (
const std::exception&) {
252 for (
size_t i = 0; i < cols_.size(); ++i) {
253 if (cols_[i] == col_name) {
262 if (col_index >= cols_.size()) {
264 " CSV file '" << filename_ <<
"' is out of range; the CSV"
265 " file has only " << cols_.size() <<
" columns ");
267 return (cols_[col_index]);
279 checkStreamStatusAndReset(
"get next row");
288 while (fs_->good() && line.empty()) {
289 std::getline(*fs_, line);
299 }
else if (!fs_->good()) {
302 setReadMsg(
"error reading a row from CSV file '"
303 + std::string(filename_) +
"'");
312 return (skip_validation ?
true :
validate(row));
318 if (size() ==
static_cast<std::streampos
>(0)) {
323 fs_.reset(
new std::fstream(filename_.c_str()));
330 if (!fs_->is_open()) {
338 << filename_ <<
"'");
343 if (!
next(header,
true)) {
345 " CSV file '" << filename_ <<
"': "
352 <<
"' in CSV file '" << filename_ <<
"': "
367 fs_->seekp(0, std::ios_base::end);
368 fs_->seekg(0, std::ios_base::end);
371 " CSV file '" << filename_ <<
"'");
376 }
catch (
const std::exception&) {
389 " created CSV file '" << filename_ <<
"'");
394 fs_.reset(
new std::fstream(filename_.c_str(), std::fstream::out));
395 if (!fs_->is_open()) {
405 *fs_ << header << std::endl;
407 }
catch (
const std::exception& ex) {
419 std::ostringstream s;
420 s <<
"the size of the row '" << row <<
"' doesn't match the number of"
446const std::string CSVRow::escape_tag(
"&#x");
456 std::string escape_chars(characters + escape_tag[0]);
460 char_pos = orig_str.find_first_of(escape_chars, prev_pos);
461 if (char_pos == std::string::npos) {
465 std::stringstream ss;
466 while (char_pos < orig_str.size()) {
468 ss << orig_str.substr(prev_pos, char_pos - prev_pos);
471 ss << escape_tag << std::hex << std::setw(2)
472 <<
static_cast<uint16_t
>(orig_str[char_pos]);
478 char_pos = orig_str.find_first_of(escape_chars, prev_pos);
481 if (char_pos == std::string::npos) {
482 ss << orig_str.substr(prev_pos, char_pos - prev_pos);
495 size_t start_pos = 0;
498 esc_pos = escaped_str.find(escape_tag, start_pos);
499 if (esc_pos == std::string::npos) {
505 std::stringstream ss;
506 while (esc_pos < escaped_str.size()) {
508 ss << escaped_str.substr(start_pos, esc_pos - start_pos);
512 unsigned int escaped_char = 0;
513 bool converted =
true;
514 size_t dig_pos = esc_pos + escape_tag.size();
515 if (dig_pos <= escaped_str.size() - 2) {
516 for (
int i = 0; i < 2; ++i) {
517 uint8_t digit = escaped_str[dig_pos];
519 if (digit >=
'a' && digit <=
'f') {
520 digit = digit -
'a' + 10;
521 }
else if (digit >=
'A' && digit <=
'F') {
522 digit = digit -
'A' + 10;
523 }
else if (digit >=
'0' && digit <=
'9') {
531 escaped_char = digit << 4;
533 escaped_char |= digit;
542 ss << static_cast<unsigned char>(escaped_char);
549 esc_pos += escape_tag.size();
556 esc_pos = escaped_str.find(escape_tag, start_pos);
559 if (esc_pos == std::string::npos) {
561 ss << escaped_str.substr(start_pos, esc_pos - start_pos);
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Exception thrown when an error occurs during CSV file processing.
Exception thrown when an unrecoverable error occurs such as disk-full on write.
std::string getColumnName(const size_t col_index) const
Returns the name of the column.
void close()
Closes the CSV file.
size_t getColumnCount() const
Returns the number of columns in the file.
virtual ~CSVFile()
Destructor.
bool exists() const
Checks if the CSV file exists and can be opened for reading.
virtual bool validate(const CSVRow &row)
Validate the row read from a file.
static CSVRow EMPTY_ROW()
Represents empty row.
void setReadMsg(const std::string &read_msg)
Sets error message after row validation.
CSVFile(const std::string &filename)
Constructor.
std::string getFilename() const
Returns the path to the CSV file.
void flush() const
Flushes a file.
virtual bool validateHeader(const CSVRow &header)
This function validates the header of the CSV file.
void addColumnInternal(const std::string &col_name)
Adds a column regardless if the file is open or not.
virtual void recreate()
Creates a new CSV file.
std::string getReadMsg() const
Returns the description of the last error returned by the CSVFile::next function.
void append(const CSVRow &row) const
Writes the CSV row into the file.
void addColumn(const std::string &col_name)
Adds new column name.
size_t getColumnIndex(const std::string &col_name) const
Returns the index of the column having specified name.
virtual void open(const bool seek_to_end=false)
Opens existing file or creates a new one.
bool next(CSVRow &row, const bool skip_validation=false)
Reads next row from CSV file.
Represents a single row of the CSV file.
std::string render() const
Creates a text representation of the CSV file row.
static std::string unescapeCharacters(const std::string &escaped_str)
Returns a copy of a string with special characters unescaped.
std::string readAtEscaped(const size_t at) const
Retrieves a value from the internal container, free of escaped characters.
size_t getValuesCount() const
Returns number of values in a CSV row.
void trim(const size_t count)
Trims a given number of elements from the end of a row.
CSVRow(const size_t cols=0, const char separator=',')
Constructor, creates the raw to be used for output.
void writeAt(const size_t at, const char *value)
Replaces the value at specified index.
static std::string escapeCharacters(const std::string &orig_str, const std::string &characters)
Returns a copy of a string with special characters escaped.
std::string readAt(const size_t at) const
Retrieves a value from the internal container.
void writeAtEscaped(const size_t at, const std::string &value)
Replaces the value at the specified index with a value that has had special characters escaped.
void parse(const std::string &line)
Parse the CSV file row.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::ostream & operator<<(std::ostream &os, const CSVRow &row)
Overrides standard output stream operator for CSVRow object.
Defines the logger used by the top-level component of kea-lfc.