A tool to construct HDR-images from a series of exposures.

csv_reader.cpp 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #include "csv_reader.h"
  2. #include <errno.h>
  3. #include <limits.h>
  4. #include <stdlib.h>
  5. #include <algorithm>
  6. #include <fstream>
  7. #include <iostream>
  8. #include <sstream>
  9. using namespace std;
  10. CSVField::CSVField(int start, int length, bool hasQuotes): start(start),
  11. length(length),
  12. hasQuotes(hasQuotes)
  13. {
  14. }
  15. CSVRow::CSVRow(string *row,
  16. const std::string * const filePath,
  17. long lineNumber,
  18. char delimiter,
  19. char quote): m_row(row),
  20. m_filePath(filePath),
  21. m_lineNumber(lineNumber),
  22. m_quote(quote)
  23. {
  24. parse(delimiter, quote);
  25. }
  26. string CSVRow::toString() const {
  27. stringstream ss;
  28. ss << "CSVRow (" << endl;
  29. if (m_lineNumber > 0) {
  30. ss << " line #: \"" << m_lineNumber << "\"" << endl;
  31. }
  32. if (m_filePath) {
  33. ss << " path: \"" << *m_filePath << "\"" << endl;
  34. }
  35. ss << " value: \"" << *m_row << "\"" << endl;
  36. for (unsigned int i = 0; i < m_fields.size(); i++) {
  37. string row;
  38. getFieldAsString(i, &row);
  39. ss << " field " << i << ": '" << row << "'" << endl;
  40. }
  41. ss << ")";
  42. return ss.str();
  43. }
  44. static bool string_to_long(const string &s, long *out) {
  45. const char *cstr = s.c_str();
  46. char *end = NULL;
  47. errno = 0;
  48. long x = strtol(cstr, &end, 10);
  49. if (errno != 0) {
  50. return false;
  51. } else if (end == &cstr[s.size()]) {
  52. *out = x;
  53. return true;
  54. } else {
  55. return false;
  56. }
  57. }
  58. static bool cstring_to_long(const char *start, const char *end, long *out) {
  59. char *parse_end = NULL;
  60. errno = 0;
  61. long x = strtol(start, &parse_end, 10);
  62. if (errno != 0) {
  63. return false;
  64. } else if (parse_end == end) {
  65. *out = x;
  66. return true;
  67. } else {
  68. return false;
  69. }
  70. }
  71. static bool string_to_double(const string &s, double *out) {
  72. const char *cstr = s.c_str();
  73. char *end = NULL;
  74. errno = 0;
  75. double x = strtod(cstr, &end);
  76. if (errno != 0) {
  77. return false;
  78. } else if (end == &cstr[s.size()]) {
  79. *out = x;
  80. return true;
  81. } else {
  82. return false;
  83. }
  84. }
  85. static bool cstring_to_double(const char *start, const char *end, double *out) {
  86. char *parse_end = NULL;
  87. errno = 0;
  88. double x = strtod(start, &parse_end);
  89. if (errno != 0) {
  90. return false;
  91. } else if (parse_end == end) {
  92. *out = x;
  93. return true;
  94. } else {
  95. return false;
  96. }
  97. }
  98. bool CSVRow::getFieldAsString(unsigned int fieldIndex, string *out) const {
  99. if (fieldIndex < m_fields.size()) {
  100. CSVField field = m_fields[fieldIndex];
  101. if (field.length == 0) {
  102. *out = "";
  103. } else {
  104. string s;
  105. if (field.hasQuotes) {
  106. s = m_row->substr(field.start, field.length);
  107. s = unquote(s, m_quote);
  108. } else {
  109. s = m_row->substr(field.start, field.length);
  110. }
  111. // remove newlines
  112. s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
  113. s.erase(std::remove(s.begin(), s.end(), '\r'), s.end());
  114. *out = s;
  115. }
  116. return true;
  117. } else {
  118. return false;
  119. }
  120. }
  121. bool CSVRow::getFieldAsLong(unsigned int fieldIndex, long *out) const {
  122. if (fieldIndex >= m_fields.size()) {
  123. return false;
  124. }
  125. if (m_fields[fieldIndex].hasQuotes) {
  126. string field;
  127. if (!getFieldAsString(fieldIndex, &field)) {
  128. return false;
  129. }
  130. return string_to_long(field, out);
  131. } else {
  132. const CSVField *field = &m_fields[fieldIndex];
  133. int sep_index = field->start + field->length;
  134. char sep = (*m_row)[sep_index];
  135. (*m_row)[sep_index] = '\0';
  136. bool ok = cstring_to_long(m_row->c_str() + field->start, m_row->c_str() + sep_index, out);
  137. (*m_row)[sep_index] = sep;
  138. return ok;
  139. }
  140. }
  141. bool CSVRow::getFieldAsInt(unsigned int fieldIndex, int *out) const {
  142. if (fieldIndex >= m_fields.size()) {
  143. return false;
  144. }
  145. long x;
  146. if (!getFieldAsLong(fieldIndex, &x)) {
  147. return false;
  148. }
  149. if (x < INT_MIN || x > INT_MAX) {
  150. // underflow or overflow
  151. return false;
  152. }
  153. *out = (int)x;
  154. return true;
  155. }
  156. bool CSVRow::getFieldAsDouble(unsigned int fieldIndex, double *out) const {
  157. if (fieldIndex >= m_fields.size()) {
  158. return false;
  159. }
  160. if (m_fields[fieldIndex].hasQuotes) {
  161. string field;
  162. if (!getFieldAsString(fieldIndex, &field)) {
  163. return false;
  164. }
  165. return string_to_double(field, out);
  166. } else {
  167. const CSVField *field = &m_fields[fieldIndex];
  168. int sep_index = field->start + field->length;
  169. char sep = (*m_row)[sep_index];
  170. (*m_row)[sep_index] = '\0';
  171. bool ok = cstring_to_double(m_row->c_str() + field->start, m_row->c_str() + sep_index, out);
  172. (*m_row)[sep_index] = sep;
  173. return ok;
  174. }
  175. }
  176. string CSVRow::getFilePath() const {
  177. if (m_filePath) {
  178. return string(*m_filePath);
  179. } else {
  180. return "";
  181. }
  182. }
  183. long CSVRow::getLineNumber() const {
  184. return m_lineNumber;
  185. }
  186. unsigned int CSVRow::getNumberOfFields() const {
  187. return m_fields.size();
  188. }
  189. void CSVRow::parse(char delimiter, char quote) {
  190. m_fields.clear();
  191. //TODO: properly handle unicode strings (could use QString::fromUtf8 and iterate over that)
  192. int start = 0;
  193. int length = -1;
  194. bool in_quotes = false;
  195. bool has_quotes = false;
  196. unsigned int size = m_row->size();
  197. // handle trailing \n and \r chars
  198. while (size > 0 && ((*m_row)[size - 1] == '\n' || (*m_row)[size - 1] == '\r')) {
  199. size--;
  200. }
  201. for (unsigned int i = 0; i < size; i++) {
  202. length++;
  203. char c = (*m_row)[i];
  204. if (c == delimiter && !in_quotes) {
  205. m_fields.push_back(CSVField(start, length, has_quotes));
  206. start = i + 1;
  207. length = -1;
  208. has_quotes = false;
  209. }
  210. if (c == quote) {
  211. has_quotes = true;
  212. if (in_quotes) {
  213. in_quotes = false;
  214. } else {
  215. in_quotes = true;
  216. }
  217. }
  218. }
  219. if (!(start == 0 && length == -1)) {
  220. length++;
  221. m_fields.push_back(CSVField(start, length, has_quotes));
  222. }
  223. }
  224. string CSVRow::unquote(const string &fieldStr, char quoteChar) {
  225. string ret;
  226. bool in_quotes = false;
  227. bool last_char_was_quote = false;
  228. //TODO: properly handle unicode strings here too
  229. for (unsigned int i = 0; i < fieldStr.size(); i++) {
  230. char c = fieldStr[i];
  231. if (in_quotes) {
  232. if (c == quoteChar) {
  233. in_quotes = false;
  234. last_char_was_quote = true;
  235. } else {
  236. ret.push_back(c);
  237. last_char_was_quote = false;
  238. }
  239. } else {
  240. if (c == quoteChar) {
  241. in_quotes = true;
  242. if (last_char_was_quote) {
  243. ret.push_back(quoteChar);
  244. }
  245. }
  246. last_char_was_quote = false;
  247. }
  248. }
  249. return ret;
  250. }
  251. string CSVRow::quote(const string &fieldStr, char quoteChar) {
  252. string ret;
  253. //TODO: properly handle unicode strings here too
  254. //TODO: optimize using string::find
  255. for (unsigned int i = 0; i < fieldStr.size(); i++) {
  256. char c = fieldStr[i];
  257. if (c == quoteChar) {
  258. ret.append(2, quoteChar);
  259. } else {
  260. ret.push_back(c);
  261. }
  262. }
  263. return ret;
  264. }
  265. bool CSVReader::readFromFile(const std::string filePath,
  266. CSVReader::RowCallback callback,
  267. void *userData,
  268. char delimiter,
  269. char quote)
  270. {
  271. ifstream stream;
  272. stream.open(filePath.c_str(), ios::in);
  273. if (stream) {
  274. bool ok = CSVReader::readFromStream(stream,
  275. callback,
  276. userData,
  277. &filePath,
  278. delimiter,
  279. quote);
  280. stream.close();
  281. return ok;
  282. } else {
  283. cerr << "Error: Cannot read file \"" << filePath << "\"" << endl;
  284. return false;
  285. }
  286. return true;
  287. }
  288. bool CSVReader::readFromStream(std::istream &stream,
  289. CSVReader::RowCallback callback,
  290. void *userData,
  291. const string * const filePath,
  292. char delimiter,
  293. char quote)
  294. {
  295. string line = "";
  296. long nr = 0;
  297. while (getline(stream, line, '\n')) {
  298. nr++;
  299. if (line.size() > 0) {
  300. CSVRow row(&line, filePath, nr, delimiter, quote);
  301. if (!callback(row, userData)) {
  302. return false;
  303. }
  304. }
  305. }
  306. return true;
  307. }