minetest-mapper-cpp/Minetestmapper/DataFileParser.cpp

245 lines
6.4 KiB
C++

#include "DataFileParser.h"
#include <climits>
#include <fstream>
#include <iostream>
using namespace std;
DataFileParser::DataFileParser(int verboseReadColors, bool drawAlpha) :
verboseReadColors(verboseReadColors),
m_drawAlpha(drawAlpha)
{
};
DataFileParser::~DataFileParser()
= default;
void DataFileParser::parseDataFile(const std::string & fileName, const char * type, int depth)
{
if (depth > 100) {
throw std::runtime_error(std::string("Excessive inclusion depth of ") + type + " files - suspected recursion (i.e. cycle); current file: '" + fileName + "'");
}
if (depth == 0 && verboseReadColors >= 2) {
cout << "Checking for " << type << " file: " << fileName << std::endl;
}
ifstream in;
in.open(fileName.c_str(), ifstream::in);
if (!in.is_open()) {
throw std::runtime_error(std::string("Failed to open ") + type + " file '" + fileName + "'");
return;
}
if (verboseReadColors >= 1) {
cout << "Reading " << type << " file: " << fileName << std::endl;
}
parseDataStream(in, fileName, depth, type);
in.close();
}
void DataFileParser::parseDataStream(std::istream & in, const std::string & filename, int depth, const char * type)
{
string line;
int linenr = 0;
for (std::getline(in, line); in.good(); std::getline(in, line)) {
linenr++;
size_t comment = line.find_first_of('#');
if (comment != string::npos) {
line.erase(comment);
}
istringstream iline;
iline.str(line);
iline >> std::skipws;
string name;
iline >> name >> std::ws;
if (name.empty()) {
continue;
}
if (name == "@include") {
string includeFile;
getline(iline, includeFile);
size_t lastChar = includeFile.find_last_not_of(" \t\r\n");
if (lastChar != string::npos) {
includeFile.erase(lastChar + 1);
}
if (includeFile.empty()) {
std::cerr << filename << ":" << linenr << ": include filename missing in colors file (" << line << ")" << std::endl;
continue;
}
if (includeFile[0] != '/') {
string includePath = filename;
size_t offset = includePath.find_last_of('/');
if (offset != string::npos) {
includePath.erase(offset);
includePath.append("/").append(includeFile);
includeFile = includePath;
}
}
parseDataFile(includeFile, type, depth + 1);
}
else {
parseLine(line, name, iline, linenr, filename);
}
}
if (!in.eof()) {
std::cerr << filename << ": error reading colors file after line " << linenr << std::endl;
}
}
void ColorsFileParser::parseLine(const std::string & line, std::string name, std::istringstream & iline, int linenr, const std::string & filename)
{
iline >> std::ws >> std::skipws;
if (iline.good() && iline.peek() == '-') {
char c;
iline >> c >> std::ws;
if (iline.fail() || !iline.eof()) {
std::cerr << filename << ":" << linenr << ": bad line in colors file (" << line << ")" << std::endl;
return;
}
m_nodeColors.erase(name);
}
else {
int r, g, b, a, t, f;
std::string flags;
ColorEntry color;
iline >> r;
iline >> g;
iline >> b;
if (iline.fail()) {
std::cerr << filename << ":" << linenr << ": bad line in colors file (" << line << ")" << std::endl;
return;
}
a = 0xff;
iline >> std::ws;
if (iline.good() && isdigit(iline.peek())) {
iline >> a >> std::ws;
}
t = 0;
if (iline.good() && isdigit(iline.peek())) {
iline >> t >> std::ws;
}
if (iline.good() && !isdigit(iline.peek())) {
iline >> flags >> std::ws;
}
f = 0;
if (!iline.fail() && !flags.empty()) {
for (char & flag : flags) {
if (flag == ',') {
flag = ' ';
}
}
istringstream iflags(flags);
std::string flag;
iflags >> flag;
while (!iflags.fail()) {
if (flag == "ignore") {
f |= ColorEntry::FlagIgnore;
}
else if (flag == "air") {
f |= ColorEntry::FlagAir;
}
iflags >> flag;
}
}
color = ColorEntry(r, g, b, a, t, f);
if ((m_drawAlpha && a == 0xff) || (!m_drawAlpha && a != 0xff)) {
// If drawing alpha, and the colors file contains both
// an opaque entry and a non-opaque entry for a name, prefer
// the non-opaque entry
// If not drawing alpha, and the colors file contains both
// an opaque entry and a non-opaque entry for a name, prefer
// the opaque entry
// Otherwise, any later entry overrides any previous entry
auto it = m_nodeColors.find(name);
if (it != m_nodeColors.end()) {
if (m_drawAlpha && (a == 0xff && it->second.a != 0xff)) {
// drawing alpha: don't use opaque color to override
// non-opaque color
return;
}
if (!m_drawAlpha && (a != 0xff && it->second.a == 0xff)) {
// not drawing alpha: don't use non-opaque color to
// override opaque color
return;
}
}
}
m_nodeColors[name] = color;
}
}
void HeightMapColorsFileParser::parseLine(const std::string & line, std::string name, std::istringstream & iline, int linenr, const std::string & filename)
{
(void)name;
int height[2];
Color color[2];
iline.str(line); // Reset
for (int & i : height) {
iline >> std::ws;
char c = iline.peek();
iline >> i;
if (iline.fail()) {
std::string value;
iline.clear();
iline >> std::ws;
iline >> value >> std::ws;
if (!iline.fail()) {
if (value == "-oo" || (c == '-' && value == "oo")) {
i = INT_MIN;
}
else if (value == "oo" || value == "+oo") {
i = INT_MAX;
}
else {
iline.clear(ios::failbit); // Set to failed
break;
}
}
}
}
for (auto & i : color) {
int r, g, b;
iline >> r;
iline >> g;
iline >> b;
i = Color(r, g, b);
}
if (height[0] > height[1]) {
{
int tmp = height[0];
height[0] = height[1];
height[1] = tmp;
}
{
Color tmp = color[0];
color[0] = color[1];
color[1] = tmp;
}
}
iline >> std::ws;
if (iline.fail() || !iline.eof()) {
std::cerr << filename << ":" << linenr << ": bad line in heightmap colors file (" << line << ")" << std::endl;
return;
}
m_heightMapColors.push_back(HeightMapColor(height[0], color[0], height[1], color[1]));
}
void HeightMapNodesFileParser::parseLine(const std::string & line, std::string name, std::istringstream & iline, int linenr, const std::string & filename)
{
if (name == "-") {
iline >> std::ws >> name >> std::ws;
m_nodeColors.erase(name);
}
else {
m_nodeColors[name] = ColorEntry(0, 0, 0, 255, 1, 0); // Dummy entry - but must not be transparent
}
// Don't care if not at eof (== really eol). We might be reading a colors.txt file...
if (iline.fail()) {
std::cerr << filename << ":" << linenr << ": bad line in heightmap nodes file (" << line << ")" << std::endl;
return;
}
}