diff --git a/Source/Ember/XmlToEmber.h b/Source/Ember/XmlToEmber.h
index 7593c72..da69128 100644
--- a/Source/Ember/XmlToEmber.h
+++ b/Source/Ember/XmlToEmber.h
@@ -295,14 +295,14 @@ public:
}
}
-///
-/// Parse the specified buffer and place the results in the vector of embers passed in.
-///
-/// The buffer to parse
-/// Full path and filename, optionally empty
-/// The newly constructed embers based on what was parsed
-/// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.
-/// True if there were no errors, else false.
+ ///
+ /// Parse the specified buffer and place the results in the vector of embers passed in.
+ ///
+ /// The buffer to parse
+ /// Full path and filename, optionally empty
+ /// The newly constructed embers based on what was parsed
+ /// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.
+ /// True if there were no errors, else false.
bool Parse(byte* buf, const char* filename, vector>& embers, bool useDefaults = true)
{
char* bn;
@@ -378,14 +378,14 @@ public:
return true;
}
-///
-/// Parse the specified file and place the results in the vector of embers passed in.
-/// This will strip out ampersands because the Xml parser can't handle them.
-///
-/// Full path and filename
-/// The newly constructed embers based on what was parsed
-/// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.
-/// True if there were no errors, else false.
+ ///
+ /// Parse the specified file and place the results in the vector of embers passed in.
+ /// This will strip out ampersands because the Xml parser can't handle them.
+ ///
+ /// Full path and filename
+ /// The newly constructed embers based on what was parsed
+ /// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.
+ /// True if there were no errors, else false.
bool Parse(const char* filename, vector>& embers, bool useDefaults = true)
{
const char* loc = __FUNCTION__;
@@ -407,13 +407,13 @@ public:
return false;
}
-///
-/// Thin wrapper around converting the string to a numeric value and return a bool indicating success.
-/// See error report for errors.
-///
-/// The string to convert
-/// The converted value
-/// True if success, else false.
+ ///
+ /// Thin wrapper around converting the string to a numeric value and return a bool indicating success.
+ /// See error report for errors.
+ ///
+ /// The string to convert
+ /// The converted value
+ /// True if success, else false.
template
bool Aton(const char* str, valT& val)
{
@@ -431,14 +431,13 @@ public:
return b;
}
-
-///
-/// Convert an integer to a string.
-/// Just a wrapper around _itoa_s() which wraps the result in a std::string.
-///
-/// The integer to convert
-/// The radix of the integer. Default: 10.
-/// The converted string
+ ///
+ /// Convert an integer to a string.
+ /// Just a wrapper around _itoa_s() which wraps the result in a std::string.
+ ///
+ /// The integer to convert
+ /// The radix of the integer. Default: 10.
+ /// The converted string
static string Itos(int i, int radix = 10)
{
char ch[16];
@@ -450,13 +449,13 @@ public:
return string(ch);
}
-///
-/// Convert an unsigned 64-bit integer to a string.
-/// Just a wrapper around _ui64toa_s() which wraps the result in a std::string.
-///
-/// The unsigned 64-bit integer to convert
-/// The radix of the integer. Default: 10.
-/// The converted string
+ ///
+ /// Convert an unsigned 64-bit integer to a string.
+ /// Just a wrapper around _ui64toa_s() which wraps the result in a std::string.
+ ///
+ /// The unsigned 64-bit integer to convert
+ /// The radix of the integer. Default: 10.
+ /// The converted string
static string Itos64(size_t i, int radix = 10)
{
char ch[64];
@@ -471,13 +470,13 @@ public:
static vector m_FlattenNames;
private:
-///
-/// Scan the file for ember nodes, and parse them out into the vector of embers.
-///
-/// The current node to parse
-/// The full path and filename
-/// The newly constructed embers based on what was parsed
-/// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present.
+ ///
+ /// Scan the file for ember nodes, and parse them out into the vector of embers.
+ ///
+ /// The current node to parse
+ /// The full path and filename
+ /// The newly constructed embers based on what was parsed
+ /// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present.
void ScanForEmberNodes(xmlNode* curNode, char* parentFile, vector>& embers, bool useDefaults)
{
bool parseEmberSuccess;
@@ -530,12 +529,12 @@ private:
}
}
-///
-/// Parse an ember element.
-///
-/// The current node to parse
-/// The newly constructed ember based on what was parsed
-/// True if there were no errors, else false.
+ ///
+ /// Parse an ember element.
+ ///
+ /// The current node to parse
+ /// The newly constructed ember based on what was parsed
+ /// True if there were no errors, else false.
bool ParseEmberElement(xmlNode* emberNode, Ember& currentEmber)
{
bool ret = true;
@@ -640,10 +639,9 @@ private:
if (sscanf_s(attStr, "%lu %lu", ¤tEmber.m_FinalRasW, ¤tEmber.m_FinalRasH) != 2)
{
AddToReport(string(loc) + " : Invalid size attribute " + string(attStr));
- xmlFree(attStr);
- //These return statements are bad. One because they are inconsistent with others that just assign defaults.
- //Two, because assigning easily guessable defaults is easy and less drastic.
- return false;
+ //Assign reasonable defaults.
+ currentEmber.m_FinalRasW = 1000;
+ currentEmber.m_FinalRasH = 1000;
}
currentEmber.m_OrigFinalRasW = currentEmber.m_FinalRasW;
@@ -654,8 +652,8 @@ private:
if (sscanf_s(attStr, "%lf %lf", &vals[0], &vals[1]) != 2)
{
AddToReport(string(loc) + " : Invalid center attribute " + string(attStr));
- xmlFree(attStr);
- return false;
+ vals[0] = 0;
+ vals[1] = 0;
}
currentEmber.m_CenterX = T(vals[0]);
@@ -686,8 +684,9 @@ private:
if (sscanf_s(attStr, "%lf %lf %lf", &vals[0], &vals[1], &vals[2]) != 3)
{
AddToReport(string(loc) + " : Invalid background attribute " + string(attStr));
- xmlFree(attStr);
- return false;
+ vals[0] = 0;
+ vals[1] = 0;
+ vals[2] = 0;
}
currentEmber.m_Background[0] = T(vals[0]);//[0..1]
@@ -1003,8 +1002,8 @@ private:
motion.m_MotionFunc = eMotion::MOTION_SAW;
else
{
- AddToReport(string(loc) + " : invalid flame motion function " + func);
- return false;
+ AddToReport(string(loc) + " : invalid flame motion function " + func + ", setting to sin");
+ motion.m_MotionFunc = eMotion::MOTION_SIN;
}
}
else if (!Compare(curAtt->name, "zoom"))
@@ -1038,8 +1037,7 @@ private:
if (sscanf_s(attStr, "%lf %lf %lf", &r, &g, &b) != 3)
{
AddToReport(string(loc) + " : Invalid flame motion background attribute " + string(attStr));
- xmlFree(attStr);
- return false;
+ r = g = b = 0;
}
if (r != 0)
@@ -1058,8 +1056,7 @@ private:
if (sscanf_s(attStr, "%lf %lf", &cx, &cy) != 2)
{
AddToReport(string(loc) + " : Invalid flame motion center attribute " + string(attStr));
- xmlFree(attStr);
- return false;
+ cx = cy = 0;
}
if (cx != 0)
@@ -1071,8 +1068,6 @@ private:
else
{
AddToReport(string(loc) + " : Unknown flame motion attribute " + string(CCX(curAtt->name)));
- xmlFree(attStr);
- return false;
}
xmlFree(attStr);
@@ -1089,17 +1084,17 @@ private:
if (soloXform >= 0 && i != soloXform)
currentEmber.GetXform(i)->m_Opacity = 0;//Will calc the cached adjusted viz value later.
- return ErrorReport().empty();
+ return true;
}
-///
-/// Parse a floating point value from an xml attribute and add the value to a EmberMotion object
-///
-/// The current attribute
-/// The attribute value to parse
-/// The flame motion parameter type
-/// The flame motion element to add the parameter to
-/// True if there were no errors, else false.
+ ///
+ /// Parse a floating point value from an xml attribute and add the value to a EmberMotion object
+ ///
+ /// The current attribute
+ /// The attribute value to parse
+ /// The flame motion parameter type
+ /// The flame motion element to add the parameter to
+ /// True if there were no errors, else false.
bool AttToEmberMotionFloat(xmlAttrPtr att, const char* attStr, eEmberMotionParam param, EmberMotion& motion)
{
const char* loc = __FUNCTION__;
@@ -1119,13 +1114,13 @@ private:
return r;
}
-///
-/// Parse an xform element.
-///
-/// The current node to parse
-/// The newly constructed xform based on what was parsed
-/// True if this xform is a motion within a parent xform, else false
-/// True if there were no errors, else false.
+ ///
+ /// Parse an xform element.
+ ///
+ /// The current node to parse
+ /// The newly constructed xform based on what was parsed
+ /// True if this xform is a motion within a parent xform, else false
+ /// True if there were no errors, else false.
bool ParseXform(xmlNode* childNode, Xform& xform, bool motion, bool fromEmber)
{
bool success = true;
@@ -1368,13 +1363,13 @@ private:
return true;
}
-///
-/// Some Apophysis plugins use an inconsistent naming scheme for the parametric variation variables.
-/// This function identifies and converts them to Ember's consistent naming convention.
-///
-/// The map of corrected names to search
-/// The current Xml node to check
-/// The corrected name if one was found, else the passed in name.
+ ///
+ /// Some Apophysis plugins use an inconsistent naming scheme for the parametric variation variables.
+ /// This function identifies and converts them to Ember's consistent naming convention.
+ ///
+ /// The map of corrected names to search
+ /// The current Xml node to check
+ /// The corrected name if one was found, else the passed in name.
static string GetCorrectedParamName(const unordered_map& names, const char* name)
{
const auto& newName = names.find(ToLower(name));
@@ -1385,15 +1380,15 @@ private:
return name;
}
-///
-/// Some Apophysis plugins use an inconsistent naming scheme for variation names.
-/// This function identifies and converts them to Ember's consistent naming convention.
-/// It uses some additional intelligence to ensure the variation is the expected one,
-/// by examining the rest of the xform for the existence of parameter names.
-///
-/// The vector of corrected names to search
-/// The current Xml node to check
-/// The corrected name if one was found, else the passed in name.
+ ///
+ /// Some Apophysis plugins use an inconsistent naming scheme for variation names.
+ /// This function identifies and converts them to Ember's consistent naming convention.
+ /// It uses some additional intelligence to ensure the variation is the expected one,
+ /// by examining the rest of the xform for the existence of parameter names.
+ ///
+ /// The vector of corrected names to search
+ /// The current Xml node to check
+ /// The corrected name if one was found, else the passed in name.
static string GetCorrectedVariationName(vector, vector>>& vec, xmlAttrPtr att)
{
for (auto& v : vec)
@@ -1418,12 +1413,12 @@ private:
return string(CCX(att->name));
}
-///
-/// Determine if an Xml node contains a given tag.
-///
-/// The Xml node to search
-/// The node name to search for
-/// True if name was found, else false.
+ ///
+ /// Determine if an Xml node contains a given tag.
+ ///
+ /// The Xml node to search
+ /// The node name to search for
+ /// True if name was found, else false.
static bool XmlContainsTag(xmlAttrPtr att, const char* name)
{
xmlAttrPtr temp = att;
@@ -1438,15 +1433,15 @@ private:
return false;
}
-///
-/// Parse hexadecimal colors.
-/// This can read RGB and RGBA, however only RGB will be stored.
-///
-/// The string of hex colors to parse
-/// The ember whose palette will be assigned the colors
-/// The number of colors present
-/// The number of channels in each color
-/// True if there were no errors, else false.
+ ///
+ /// Parse hexadecimal colors.
+ /// This can read RGB and RGBA, however only RGB will be stored.
+ ///
+ /// The string of hex colors to parse
+ /// The ember whose palette will be assigned the colors
+ /// The number of colors present
+ /// The number of channels in each color
+ /// True if there were no errors, else false.
bool ParseHexColors(char* colstr, Ember& ember, size_t numColors, intmax_t chan)
{
size_t colorIndex = 0;
@@ -1509,15 +1504,15 @@ private:
return ok;
}
-///
-/// Wrapper to parse a numeric Xml string value and convert it.
-///
-/// The xml tag to parse
-/// The name of the Xml attribute
-/// The name of the Xml tag
-/// The parsed value
-/// Bitwise ANDed with true if name matched str and the conversion succeeded, else false. Used for keeping a running value between successive calls.
-/// True if the tag was matched and the conversion succeeded, else false
+ ///
+ /// Wrapper to parse a numeric Xml string value and convert it.
+ ///
+ /// The xml tag to parse
+ /// The name of the Xml attribute
+ /// The name of the Xml tag
+ /// The parsed value
+ /// Bitwise ANDed with true if name matched str and the conversion succeeded, else false. Used for keeping a running value between successive calls.
+ /// True if the tag was matched and the conversion succeeded, else false
template
bool ParseAndAssign(const xmlChar* name, const char* attStr, const char* str, valT& val, bool& b)
{
diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp
index 55193d5..e6d9dfd 100644
--- a/Source/Fractorium/FractoriumMenus.cpp
+++ b/Source/Fractorium/FractoriumMenus.cpp
@@ -172,6 +172,7 @@ void FractoriumEmberController::OpenAndPrepFiles(const QStringList& filenames
EmberFile emberFile;
XmlToEmber parser;
vector> embers;
+ vector errors;
uint previousSize = append ? uint(m_EmberFile.Size()) : 0u;
StopPreviewRender();
emberFile.m_Filename = filenames[0];
@@ -196,13 +197,16 @@ void FractoriumEmberController::OpenAndPrepFiles(const QStringList& filenames
m_LastSaveAll = "";
emberFile.m_Embers.insert(emberFile.m_Embers.end(), embers.begin(), embers.end());
+ errors = parser.ErrorReport();
}
else
{
- auto errors = parser.ErrorReport();
- m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
+ errors = parser.ErrorReport();
m_Fractorium->ShowCritical("Open Failed", "Could not open file, see info tab for details.");
}
+
+ if (!errors.empty())
+ m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
}
if (append)