Visual Computing Library
Loading...
Searching...
No Matches
read.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_IO_READ_H
24#define VCL_IO_READ_H
25
26#include "file_info.h"
27#include "serialization/deserialize.h"
28
29#include <vclib/concepts/mesh/elements/element.h>
30#include <vclib/misc/string.h>
31#include <vclib/misc/tokenizer.h>
32
33namespace vcl {
34
35namespace detail {
36
50template<bool THROW = true>
51inline std::string readNextNonEmptyLine(std::istream& file)
52{
53 std::string line;
54 do {
55 std::getline(file, line);
56 if constexpr (THROW) {
57 if (!file) {
58 throw MalformedFileException("Unexpected end of file.");
59 }
60 }
61 if (file && line.size() > 0) {
62 removeCarriageReturn(line);
63 }
64 } while (file && line.size() == 0);
65 return line;
66}
67
68} // namespace detail
69
80inline std::ifstream openInputFileStream(
81 const std::string& filename,
82 const std::string& ext = "")
83{
84 setlocale(LC_ALL, "C");
85
86 std::string actualfilename = filename;
87 if (!ext.empty()) {
88 actualfilename = FileInfo::addExtensionIfNeeded(filename, ext);
89 }
90 // need to set binary or windows will fail
91 std::ifstream fp(actualfilename, std::ifstream::binary);
92 fp.imbue(std::locale().classic());
93
94 if (!fp.is_open()) {
95 throw CannotOpenFileException(filename);
96 }
97 return fp;
98}
99
109inline std::string readNextNonEmptyLine(std::istream& file)
110{
111 return detail::readNextNonEmptyLine<>(file);
112}
113
121inline std::string readNextNonEmptyLineNoThrow(std::istream& file)
122{
123 return detail::readNextNonEmptyLine<false>(file);
124}
125
138inline Tokenizer readAndTokenizeNextNonEmptyLine(
139 std::istream& file,
140 std::vector<char> separators = {' ', '\t'})
141{
142 std::string line;
143 Tokenizer tokenizer;
144
145 do {
146 line = readNextNonEmptyLine(file);
147 tokenizer = Tokenizer(line, separators);
148 } while (tokenizer.begin() == tokenizer.end());
149
150 return tokenizer;
151}
152
163inline Tokenizer readAndTokenizeNextNonEmptyLineNoThrow(
164 std::istream& file,
165 std::vector<char> separators = {' ', '\t'})
166{
167 std::string line;
168 Tokenizer tokenizer;
169
170 do {
171 line = readNextNonEmptyLineNoThrow(file);
172 tokenizer = Tokenizer(line, separators);
173 } while (file && tokenizer.begin() == tokenizer.end());
174
175 return tokenizer;
176}
177
178namespace io {
179
180// read/bin
181
182// TODO: add isColor parameter also in integral read functions - and then
183// divide by 255 if T is not integral
184
194template<typename T>
195T readChar(std::istream& file, std::endian end = std::endian::native)
196{
197 char c;
198 deserialize(file, c, end);
199 return static_cast<T>(c);
200}
201
211template<typename T>
212T readUChar(std::istream& file, std::endian end = std::endian::native)
213{
214 unsigned char c;
215 deserialize(file, c, end);
216 return static_cast<T>(c);
217}
218
228template<typename T>
229T readShort(std::istream& file, std::endian end = std::endian::native)
230{
231 short c;
232 deserialize(file, c, end);
233 return static_cast<T>(c);
234}
235
245template<typename T>
246T readUShort(std::istream& file, std::endian end = std::endian::native)
247{
248 unsigned short c;
249 deserialize(file, c, end);
250 return static_cast<T>(c);
251}
252
262template<typename T>
263T readInt(std::istream& file, std::endian end = std::endian::native)
264{
265 int c;
266 deserialize(file, c, end);
267 return static_cast<T>(c);
268}
269
279template<typename T>
280T readUInt(std::istream& file, std::endian end = std::endian::native)
281{
282 uint c;
283 deserialize(file, c, end);
284 return static_cast<T>(c);
285}
286
302template<typename T>
303T readFloat(
304 std::istream& file,
305 std::endian end = std::endian::native,
306 bool isColor = false)
307{
308 float c;
309 deserialize(file, c, end);
310 if constexpr (std::integral<T>) {
311 if (isColor)
312 return static_cast<T>(c * 255);
313 }
314 return static_cast<T>(c);
315}
316
332template<typename T>
333T readDouble(
334 std::istream& file,
335 std::endian end = std::endian::native,
336 bool isColor = false)
337{
338 double c;
339 deserialize(file, c, end);
340 if constexpr (std::integral<T>) {
341 if (isColor)
342 return static_cast<T>(c * 255);
343 }
344 return static_cast<T>(c);
345}
346
367template<typename T>
368T readPrimitiveType(
369 std::istream& file,
370 PrimitiveType type,
371 std::endian end = std::endian::native,
372 bool isColor = false)
373{
374 T p;
375 switch (type) {
376 case PrimitiveType::CHAR: p = readChar<T>(file, end); break;
377 case PrimitiveType::UCHAR: p = readUChar<T>(file, end); break;
378 case PrimitiveType::SHORT: p = readShort<T>(file, end); break;
379 case PrimitiveType::USHORT: p = readUShort<T>(file, end); break;
380 case PrimitiveType::INT: p = readInt<T>(file, end); break;
381 case PrimitiveType::UINT: p = readUInt<T>(file, end); break;
382 case PrimitiveType::FLOAT: p = readFloat<T>(file, end, isColor); break;
383 case PrimitiveType::DOUBLE: p = readDouble<T>(file, end, isColor); break;
384 default: assert(0); p = 0;
385 }
386 // if I read a color that must be returned as a float or double
387 if (isColor && !std::is_integral<T>::value)
388 p /= 255.0;
389 return p;
390}
391
392template<ElementConcept El>
393void readCustomComponent(
394 std::istream& file,
395 El& elem,
396 const std::string& cName,
397 PrimitiveType type,
398 std::endian end = std::endian::native)
399{
400 std::type_index ti = elem.customComponentType(cName);
401 if (ti == typeid(char))
402 elem.template customComponent<char>(cName) =
403 readPrimitiveType<char>(file, type, end);
404 else if (ti == typeid(unsigned char))
405 elem.template customComponent<unsigned char>(cName) =
406 readPrimitiveType<unsigned char>(file, type, end);
407 else if (ti == typeid(short))
408 elem.template customComponent<short>(cName) =
409 readPrimitiveType<short>(file, type, end);
410 else if (ti == typeid(unsigned short))
411 elem.template customComponent<unsigned short>(cName) =
412 readPrimitiveType<unsigned short>(file, type, end);
413 else if (ti == typeid(int))
414 elem.template customComponent<int>(cName) =
415 readPrimitiveType<int>(file, type, end);
416 else if (ti == typeid(unsigned int))
417 elem.template customComponent<uint>(cName) =
418 readPrimitiveType<uint>(file, type, end);
419 else if (ti == typeid(float))
420 elem.template customComponent<float>(cName) =
421 readPrimitiveType<float>(file, type, end);
422 else if (ti == typeid(double))
423 elem.template customComponent<double>(cName) =
424 readPrimitiveType<double>(file, type, end);
425 else
426 assert(0);
427}
428
429// read/txt
430
431template<typename T>
432T readChar(Tokenizer::iterator& token, std::endian = std::endian::native)
433{
434 return std::stoi(*token++);
435}
436
437template<typename T>
438T readUChar(Tokenizer::iterator& token, std::endian = std::endian::native)
439{
440 return std::stoi(*token++);
441}
442
443template<typename T>
444T readShort(Tokenizer::iterator& token, std::endian = std::endian::native)
445{
446 return std::stoi(*token++);
447}
448
449template<typename T>
450T readUShort(Tokenizer::iterator& token, std::endian = std::endian::native)
451{
452 return std::stoi(*token++);
453}
454
455template<typename T>
456T readInt(Tokenizer::iterator& token, std::endian = std::endian::native)
457{
458 return std::stoi(*token++);
459}
460
461template<typename T>
462T readUInt(Tokenizer::iterator& token, std::endian = std::endian::native)
463{
464 return std::stoi(*token++);
465}
466
467template<typename T>
468T readFloat(
469 Tokenizer::iterator& token,
470 std::endian = std::endian::native,
471 bool isColor = false)
472{
473 if (isColor && std::is_integral<T>::value) {
474 return std::stod(*token++) * 255;
475 }
476 else {
477 return std::stod(*token++);
478 }
479}
480
481template<typename T>
482T readDouble(
483 Tokenizer::iterator& token,
484 std::endian = std::endian::native,
485 bool isColor = false)
486{
487 if (isColor && std::is_integral<T>::value) {
488 return std::stod(*token++) * 255;
489 }
490 else {
491 return std::stod(*token++);
492 }
493}
494
495template<typename T>
496T readPrimitiveType(
497 Tokenizer::iterator& token,
498 PrimitiveType type,
499 std::endian = std::endian::native,
500 bool isColor = false)
501{
502 T p;
503 switch (type) {
504 case PrimitiveType::CHAR:
505 case PrimitiveType::UCHAR:
506 case PrimitiveType::SHORT:
507 case PrimitiveType::USHORT:
508 case PrimitiveType::INT:
509 case PrimitiveType::UINT: p = std::stoi(*token++); break;
510 case PrimitiveType::FLOAT:
511 case PrimitiveType::DOUBLE:
512 if (isColor) {
513 p = std::stod(*token++) * 255;
514 }
515 else {
516 p = std::stod(*token++);
517 }
518 break;
519 default: assert(0); p = 0;
520 }
521 // if I read a color that must be returned as a float or double
522 if (isColor && !std::is_integral<T>::value)
523 p /= 255.0;
524 return p;
525}
526
527template<ElementConcept El>
528void readCustomComponent(
529 Tokenizer::iterator& token,
530 El& elem,
531 const std::string& cName,
532 PrimitiveType type,
533 std::endian = std::endian::native)
534{
535 std::type_index ti = elem.customComponentType(cName);
536 if (ti == typeid(char))
537 elem.template customComponent<char>(cName) =
538 readPrimitiveType<char>(token, type);
539 else if (ti == typeid(unsigned char))
540 elem.template customComponent<unsigned char>(cName) =
541 readPrimitiveType<unsigned char>(token, type);
542 else if (ti == typeid(short))
543 elem.template customComponent<short>(cName) =
544 readPrimitiveType<short>(token, type);
545 else if (ti == typeid(unsigned short))
546 elem.template customComponent<unsigned short>(cName) =
547 readPrimitiveType<unsigned short>(token, type);
548 else if (ti == typeid(int))
549 elem.template customComponent<int>(cName) =
550 readPrimitiveType<int>(token, type);
551 else if (ti == typeid(unsigned int))
552 elem.template customComponent<uint>(cName) =
553 readPrimitiveType<uint>(token, type);
554 else if (ti == typeid(float))
555 elem.template customComponent<float>(cName) =
556 readPrimitiveType<float>(token, type);
557 else if (ti == typeid(double))
558 elem.template customComponent<double>(cName) =
559 readPrimitiveType<double>(token, type);
560 else
561 assert(0);
562}
563
564} // namespace io
565} // namespace vcl
566
567#endif // VCL_IO_READ_H
static std::string addExtensionIfNeeded(const std::string &filename, const std::string &ext)
Adds an extension to a file name if it doesn't already have it.
Definition file_info.h:271
PrimitiveType
A simple type that enumerates the main primitive types.
Definition base.h:58