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");
172 << row.getValuesCount() <<
"' doesn't match the number of"
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;
193 << text <<
"' to the file '" << filename_ <<
"'");
198CSVFile::checkStreamStatusAndReset(
const std::string& operation)
const {
201 << operation <<
"' on file '" << filename_ <<
"'");
203 }
else if (!fs_->is_open()) {
205 isc_throw(CSVFileError,
"closed stream when performing '"
206 << operation <<
"' on file '" << filename_ <<
"'");
214CSVFile::size()
const {
215 std::ifstream fs(filename_.c_str());
223 std::ifstream::pos_type pos;
227 fs.seekg(0, std::ifstream::end);
230 }
catch (
const std::exception&) {
238 for (
size_t i = 0; i < cols_.size(); ++i) {
239 if (cols_[i] == col_name) {
248 if (col_index >= cols_.size()) {
250 " CSV file '" << filename_ <<
"' is out of range; the CSV"
251 " file has only " << cols_.size() <<
" columns ");
253 return (cols_[col_index]);
265 checkStreamStatusAndReset(
"get next row");
274 while (fs_->good() && line.empty()) {
275 std::getline(*fs_, line);
285 }
else if (!fs_->good()) {
288 setReadMsg(
"error reading a row from CSV file '"
289 + std::string(filename_) +
"'");
298 return (skip_validation ?
true :
validate(row));
304 if (size() ==
static_cast<std::streampos
>(0)) {
309 fs_.reset(
new std::fstream(filename_.c_str()));
316 if (!fs_->is_open()) {
324 << filename_ <<
"'");
329 if (!
next(header,
true)) {
331 " CSV file '" << filename_ <<
"': "
338 <<
"' in CSV file '" << filename_ <<
"': "
345 for (
size_t i = 0; i < header.getValuesCount(); ++i) {
353 fs_->seekp(0, std::ios_base::end);
354 fs_->seekg(0, std::ios_base::end);
357 " CSV file '" << filename_ <<
"'");
362 }
catch (
const std::exception&) {
375 " created CSV file '" << filename_ <<
"'");
380 fs_.reset(
new std::fstream(filename_.c_str(), std::fstream::out));
381 if (!fs_->is_open()) {
391 *fs_ << header << std::endl;
393 }
catch (
const std::exception& ex) {
405 std::ostringstream s;
406 s <<
"the size of the row '" << row <<
"' doesn't match the number of"
432const std::string CSVRow::escape_tag(
"&#x");
442 std::string escape_chars(characters + escape_tag[0]);
446 char_pos = orig_str.find_first_of(escape_chars, prev_pos);
447 if (char_pos == std::string::npos) {
451 std::stringstream ss;
452 while (char_pos < orig_str.size()) {
454 ss << orig_str.substr(prev_pos, char_pos - prev_pos);
457 ss << escape_tag << std::hex << std::setw(2)
458 <<
static_cast<uint16_t
>(orig_str[char_pos]);
464 char_pos = orig_str.find_first_of(escape_chars, prev_pos);
467 if (char_pos == std::string::npos) {
468 ss << orig_str.substr(prev_pos, char_pos - prev_pos);
481 size_t start_pos = 0;
484 esc_pos = escaped_str.find(escape_tag, start_pos);
485 if (esc_pos == std::string::npos) {
491 std::stringstream ss;
492 while (esc_pos < escaped_str.size()) {
494 ss << escaped_str.substr(start_pos, esc_pos - start_pos);
498 unsigned int escaped_char = 0;
499 bool converted =
true;
500 size_t dig_pos = esc_pos + escape_tag.size();
501 if (dig_pos <= escaped_str.size() - 2) {
502 for (
int i = 0; i < 2; ++i) {
503 uint8_t digit = escaped_str[dig_pos];
505 if (digit >=
'a' && digit <=
'f') {
506 digit = digit -
'a' + 10;
507 }
else if (digit >=
'A' && digit <=
'F') {
508 digit = digit -
'A' + 10;
509 }
else if (digit >=
'0' && digit <=
'9') {
517 escaped_char = digit << 4;
519 escaped_char |= digit;
528 ss << static_cast<unsigned char>(escaped_char);
535 esc_pos += escape_tag.size();
542 esc_pos = escaped_str.find(escape_tag, start_pos);
545 if (esc_pos == std::string::npos) {
547 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.
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.
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.