Formspec: Unify argument checks (#11851)

This commit is contained in:
SmallJoker 2021-12-29 23:58:26 +01:00 committed by GitHub
parent 0ea8df4d64
commit 14c7fae378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 1235 additions and 1303 deletions

@ -81,6 +81,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
" specified: \"" << parts[b] << "\"" << std::endl; \ " specified: \"" << parts[b] << "\"" << std::endl; \
return; \ return; \
} }
#define MY_CHECKCLIENT(a) \
if (!m_client) { \
errorstream << "Attempted to use element " << a << " with m_client == nullptr." << std::endl; \
return; \
}
/* /*
GUIFormSpecMenu GUIFormSpecMenu
*/ */
@ -294,8 +301,20 @@ v2s32 GUIFormSpecMenu::getRealCoordinateGeometry(const std::vector<std::string>
return v2s32(stof(v_geom[0]) * imgsize.X, stof(v_geom[1]) * imgsize.Y); return v2s32(stof(v_geom[0]) * imgsize.X, stof(v_geom[1]) * imgsize.Y);
} }
bool GUIFormSpecMenu::precheckElement(const std::string &name, const std::string &element,
size_t args_min, size_t args_max, std::vector<std::string> &parts)
{
parts = split(element, ';');
if (parts.size() >= args_min && (parts.size() <= args_max || m_formspec_version > FORMSPEC_API_VERSION))
return true;
errorstream << "Invalid " << name << " element(" << parts.size() << "): '" << element << "'" << std::endl;
return false;
}
void GUIFormSpecMenu::parseSize(parserData* data, const std::string &element) void GUIFormSpecMenu::parseSize(parserData* data, const std::string &element)
{ {
// Note: do not use precheckElement due to "," separator.
std::vector<std::string> parts = split(element,','); std::vector<std::string> parts = split(element,',');
if (((parts.size() == 2) || parts.size() == 3) || if (((parts.size() == 2) || parts.size() == 3) ||
@ -349,14 +368,9 @@ void GUIFormSpecMenu::parseContainerEnd(parserData* data)
void GUIFormSpecMenu::parseScrollContainer(parserData *data, const std::string &element) void GUIFormSpecMenu::parseScrollContainer(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("scroll_container start", element, 4, 5, parts))
if (parts.size() < 4 ||
(parts.size() > 5 && m_formspec_version <= FORMSPEC_API_VERSION)) {
errorstream << "Invalid scroll_container start element (" << parts.size()
<< "): '" << element << "'" << std::endl;
return; return;
}
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ','); std::vector<std::string> v_geom = split(parts[1], ',');
@ -445,16 +459,12 @@ void GUIFormSpecMenu::parseScrollContainerEnd(parserData *data)
void GUIFormSpecMenu::parseList(parserData *data, const std::string &element) void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
{ {
if (m_client == 0) { MY_CHECKCLIENT("list");
warningstream<<"invalid use of 'list' with m_client==0"<<std::endl;
std::vector<std::string> parts;
if (!precheckElement("list", element, 4, 5, parts))
return; return;
}
std::vector<std::string> parts = split(element,';');
if (((parts.size() == 4) || (parts.size() == 5)) ||
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::string location = parts[0]; std::string location = parts[0];
std::string listname = parts[1]; std::string listname = parts[1];
std::vector<std::string> v_pos = split(parts[2],','); std::vector<std::string> v_pos = split(parts[2],',');
@ -533,17 +543,11 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
m_inventorylists.push_back(e); m_inventorylists.push_back(e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid list element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseListRing(parserData *data, const std::string &element) void GUIFormSpecMenu::parseListRing(parserData *data, const std::string &element)
{ {
if (m_client == 0) { MY_CHECKCLIENT("listring");
errorstream << "WARNING: invalid use of 'listring' with m_client==0" << std::endl;
return;
}
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts = split(element, ';');
@ -578,11 +582,10 @@ void GUIFormSpecMenu::parseListRing(parserData *data, const std::string &element
void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element) void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("checkbox", element, 3, 4, parts))
return;
if (((parts.size() >= 3) && (parts.size() <= 4)) ||
((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::string name = parts[1]; std::string name = parts[1];
std::string label = parts[2]; std::string label = parts[2];
@ -650,16 +653,14 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element
e->grab(); e->grab();
m_checkboxes.emplace_back(spec, e); m_checkboxes.emplace_back(spec, e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid checkbox element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &element) void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("scrollbar", element, 5, 5, parts))
return;
if (parts.size() >= 5) {
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[3]; std::string name = parts[3];
@ -725,10 +726,6 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
m_scrollbars.emplace_back(spec,e); m_scrollbars.emplace_back(spec,e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream << "Invalid scrollbar element(" << parts.size() << "): '" << element
<< "'" << std::endl;
} }
void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string &element) void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string &element)
@ -786,11 +783,11 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element) void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("image", element, 2, 3, parts))
return;
if ((parts.size() == 3) || if (parts.size() >= 3) {
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = unescape_string(parts[2]); std::string name = unescape_string(parts[2]);
@ -842,7 +839,8 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
return; return;
} }
if (parts.size() == 2) { // Else: 2 arguments in "parts"
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::string name = unescape_string(parts[1]); std::string name = unescape_string(parts[1]);
@ -875,21 +873,13 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
// images should let events through // images should let events through
e->grab(); e->grab();
m_clickthrough_elements.push_back(e); m_clickthrough_elements.push_back(e);
return;
}
errorstream<< "Invalid image element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element) void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("animated_image", element, 6, 7, parts))
if (parts.size() != 6 && parts.size() != 7 &&
!(parts.size() > 7 && m_formspec_version > FORMSPEC_API_VERSION)) {
errorstream << "Invalid animated_image element(" << parts.size()
<< "): '" << element << "'" << std::endl;
return; return;
}
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ','); std::vector<std::string> v_geom = split(parts[1], ',');
@ -944,17 +934,16 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &element) void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("item_image", element, 3, 3, parts))
return;
if ((parts.size() == 3) ||
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2]; std::string name = parts[2];
MY_CHECKPOS("itemimage",0); MY_CHECKPOS("item_image",0);
MY_CHECKGEOM("itemimage",1); MY_CHECKGEOM("item_image",1);
v2s32 pos; v2s32 pos;
v2s32 geom; v2s32 geom;
@ -989,19 +978,15 @@ void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &elemen
m_clickthrough_elements.push_back(e); m_clickthrough_elements.push_back(e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid ItemImage element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element, void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
const std::string &type) const std::string &type)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("button", element, 4, 4, parts))
return;
if ((parts.size() == 4) ||
((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2]; std::string name = parts[2];
@ -1057,17 +1042,14 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
} }
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid button element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element) void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("background", element, 3, 5, parts))
return;
if ((parts.size() >= 3 && parts.size() <= 5) ||
(parts.size() > 5 && m_formspec_version > FORMSPEC_API_VERSION)) {
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = unescape_string(parts[2]); std::string name = unescape_string(parts[2]);
@ -1153,9 +1135,6 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
m_backgrounds.push_back(e); m_backgrounds.push_back(e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid background element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseTableOptions(parserData* data, const std::string &element) void GUIFormSpecMenu::parseTableOptions(parserData* data, const std::string &element)
@ -1192,11 +1171,10 @@ void GUIFormSpecMenu::parseTableColumns(parserData* data, const std::string &ele
void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element) void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("table", element, 4, 5, parts))
return;
if (((parts.size() == 4) || (parts.size() == 5)) ||
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2]; std::string name = parts[2];
@ -1260,18 +1238,14 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
m_tables.emplace_back(spec, e); m_tables.emplace_back(spec, e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid table element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element) void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("textlist", element, 4, 6, parts))
return;
if (((parts.size() == 4) || (parts.size() == 5) || (parts.size() == 6)) ||
((parts.size() > 6) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2]; std::string name = parts[2];
@ -1338,18 +1312,14 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
m_tables.emplace_back(spec, e); m_tables.emplace_back(spec, e);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid textlist element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element) void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("dropdown", element, 5, 6, parts))
return;
if (parts.size() == 5 || parts.size() == 6 ||
(parts.size() > 6 && m_formspec_version > FORMSPEC_API_VERSION))
{
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::string name = parts[2]; std::string name = parts[2];
std::vector<std::string> items = split(parts[3], ','); std::vector<std::string> items = split(parts[3], ',');
@ -1423,29 +1393,23 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element
for (const std::string &item : items) { for (const std::string &item : items) {
values.push_back(unescape_string(item)); values.push_back(unescape_string(item));
} }
return;
}
errorstream << "Invalid dropdown element(" << parts.size() << "): '" << element
<< "'" << std::endl;
} }
void GUIFormSpecMenu::parseFieldCloseOnEnter(parserData *data, const std::string &element) void GUIFormSpecMenu::parseFieldCloseOnEnter(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (parts.size() == 2 || if (!precheckElement("field_close_on_enter", element, 2, 2, parts))
(parts.size() > 2 && m_formspec_version > FORMSPEC_API_VERSION)) { return;
field_close_on_enter[parts[0]] = is_yes(parts[1]); field_close_on_enter[parts[0]] = is_yes(parts[1]);
}
} }
void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element) void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("pwdfield", element, 4, 4, parts))
return;
if (parts.size() == 4 ||
(parts.size() > 4 && m_formspec_version > FORMSPEC_API_VERSION))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2]; std::string name = parts[2];
@ -1521,9 +1485,6 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
// warning referring to field_close_on_enter[]! // warning referring to field_close_on_enter[]!
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid pwdfield element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec, void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
@ -1710,31 +1671,26 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
void GUIFormSpecMenu::parseField(parserData* data, const std::string &element, void GUIFormSpecMenu::parseField(parserData* data, const std::string &element,
const std::string &type) const std::string &type)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement(type, element, 3, 5, parts))
return;
if (parts.size() == 3 || parts.size() == 4) { if (parts.size() == 3 || parts.size() == 4) {
parseSimpleField(data,parts); parseSimpleField(data, parts);
return; return;
} }
if ((parts.size() == 5) || // Else: >= 5 arguments in "parts"
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) parseTextArea(data, parts, type);
{
parseTextArea(data,parts,type);
return;
}
errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &element) void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); MY_CHECKCLIENT("list");
if (parts.size() != 4 && std::vector<std::string> parts;
(parts.size() < 4 || m_formspec_version <= FORMSPEC_API_VERSION)) { if (!precheckElement("hypertext", element, 4, 4, parts))
errorstream << "Invalid hypertext element(" << parts.size() << "): '" << element << "'" << std::endl;
return; return;
}
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ','); std::vector<std::string> v_geom = split(parts[1], ',');
@ -1785,11 +1741,10 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element) void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("label", element, 2, 2, parts))
return;
if ((parts.size() == 2) ||
((parts.size() > 2) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::string text = parts[1]; std::string text = parts[1];
@ -1874,20 +1829,14 @@ void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
e->grab(); e->grab();
m_clickthrough_elements.push_back(e); m_clickthrough_elements.push_back(e);
} }
return;
}
errorstream << "Invalid label element(" << parts.size() << "): '" << element
<< "'" << std::endl;
} }
void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &element) void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("vertlabel", element, 2, 2, parts))
return;
if ((parts.size() == 2) ||
((parts.size() > 2) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::wstring text = unescape_translate( std::wstring text = unescape_translate(
unescape_string(utf8_to_wide(parts[1]))); unescape_string(utf8_to_wide(parts[1])));
@ -1958,27 +1907,29 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &elemen
// vertlabels should let events through // vertlabels should let events through
e->grab(); e->grab();
m_clickthrough_elements.push_back(e); m_clickthrough_elements.push_back(e);
return;
}
errorstream<< "Invalid vertlabel element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &element, void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &element,
const std::string &type) const std::string &type)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("image_button", element, 5, 8, parts))
return;
if (parts.size() == 6) {
// Invalid argument count.
errorstream << "Invalid image_button element(" << parts.size() << "): '" << element << "'" << std::endl;
return;
}
if ((((parts.size() >= 5) && (parts.size() <= 8)) && (parts.size() != 6)) ||
((parts.size() > 8) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string image_name = parts[2]; std::string image_name = parts[2];
std::string name = parts[3]; std::string name = parts[3];
std::string label = parts[4]; std::string label = parts[4];
MY_CHECKPOS("imagebutton",0); MY_CHECKPOS("image_button",0);
MY_CHECKGEOM("imagebutton",1); MY_CHECKGEOM("image_button",1);
std::string pressed_image_name; std::string pressed_image_name;
@ -2046,20 +1997,22 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem
e->setScaleImage(true); e->setScaleImage(true);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream<< "Invalid imagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &element) void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("tabheader", element, 4, 7, parts))
return;
// Length 7: Additional "height" parameter after "pos". Only valid with real_coordinates.
// Note: New arguments for the "height" syntax cannot be added without breaking older clients.
if (parts.size() == 5 || (parts.size() == 7 && !data->real_coordinates)) {
errorstream << "Invalid tabheader element(" << parts.size() << "): '"
<< element << "'" << std::endl;
return;
}
if (((parts.size() == 4) || (parts.size() == 6)) || (parts.size() == 7 &&
data->real_coordinates) || ((parts.size() > 6) &&
(m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
// If we're using real coordinates, add an extra field for height. // If we're using real coordinates, add an extra field for height.
@ -2158,25 +2111,16 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
e->setActiveTab(tab_index); e->setActiveTab(tab_index);
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream << "Invalid TabHeader element(" << parts.size() << "): '"
<< element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element) void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element)
{ {
if (m_client == 0) { MY_CHECKCLIENT("item_image_button");
warningstream << "invalid use of item_image_button with m_client==0"
<< std::endl; std::vector<std::string> parts;
if (!precheckElement("item_image_button", element, 5, 5, parts))
return; return;
}
std::vector<std::string> parts = split(element,';');
if ((parts.size() == 5) ||
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],','); std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],','); std::vector<std::string> v_geom = split(parts[1],',');
std::string item_name = parts[2]; std::string item_name = parts[2];
@ -2186,8 +2130,8 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
label = unescape_string(label); label = unescape_string(label);
item_name = unescape_string(item_name); item_name = unescape_string(item_name);
MY_CHECKPOS("itemimagebutton",0); MY_CHECKPOS("item_image_button",0);
MY_CHECKGEOM("itemimagebutton",1); MY_CHECKGEOM("item_image_button",1);
v2s32 pos; v2s32 pos;
v2s32 geom; v2s32 geom;
@ -2242,18 +2186,14 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
rect += data->basepos-padding; rect += data->basepos-padding;
spec_btn.rect = rect; spec_btn.rect = rect;
m_fields.push_back(spec_btn); m_fields.push_back(spec_btn);
return;
}
errorstream<< "Invalid ItemImagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element) void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("box", element, 3, 3, parts))
return;
if ((parts.size() == 3) ||
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ','); std::vector<std::string> v_geom = split(parts[1], ',');
@ -2305,19 +2245,17 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
e->drop(); e->drop();
m_fields.push_back(spec); m_fields.push_back(spec);
return;
}
errorstream << "Invalid Box element(" << parts.size() << "): '" << element
<< "'" << std::endl;
} }
void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &element) void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (!precheckElement("bgcolor", element, 2, 3, parts))
return;
const u32 parameter_count = parts.size(); const u32 parameter_count = parts.size();
if ((parameter_count > 2 && m_formspec_version < 3) || if (parameter_count > 2 && m_formspec_version < 3) {
(parameter_count > 3 && m_formspec_version <= FORMSPEC_API_VERSION)) {
errorstream << "Invalid bgcolor element(" << parameter_count << "): '" errorstream << "Invalid bgcolor element(" << parameter_count << "): '"
<< element << "'" << std::endl; << element << "'" << std::endl;
return; return;
@ -2348,11 +2286,19 @@ void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &
void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &element) void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
// Legacy Note: If clients older than 5.5.0-dev are supplied with additional arguments,
// the tooltip colors will be ignored.
if (!precheckElement("listcolors", element, 2, 5, parts))
return;
if (parts.size() == 4) {
// Invalid argument combination
errorstream << "Invalid listcolors element(" << parts.size() << "): '"
<< element << "'" << std::endl;
return;
}
if (((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) ||
((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
parseColorString(parts[0], data->inventorylist_options.slotbg_n, false); parseColorString(parts[0], data->inventorylist_options.slotbg_n, false);
parseColorString(parts[1], data->inventorylist_options.slotbg_h, false); parseColorString(parts[1], data->inventorylist_options.slotbg_h, false);
@ -2362,7 +2308,7 @@ void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &eleme
data->inventorylist_options.slotborder = true; data->inventorylist_options.slotborder = true;
} }
} }
if (parts.size() == 5) { if (parts.size() >= 5) {
video::SColor tmp_color; video::SColor tmp_color;
if (parseColorString(parts[3], tmp_color, false)) if (parseColorString(parts[3], tmp_color, false))
@ -2378,19 +2324,13 @@ void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &eleme
e->setSlotBorders(data->inventorylist_options.slotborder, e->setSlotBorders(data->inventorylist_options.slotborder,
data->inventorylist_options.slotbordercolor); data->inventorylist_options.slotbordercolor);
} }
return;
}
errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl;
} }
void GUIFormSpecMenu::parseTooltip(parserData* data, const std::string &element) void GUIFormSpecMenu::parseTooltip(parserData* data, const std::string &element)
{ {
std::vector<std::string> parts = split(element,';'); std::vector<std::string> parts;
if (parts.size() < 2) { if (!precheckElement("tooltip", element, 2, 5, parts))
errorstream << "Invalid tooltip element(" << parts.size() << "): '"
<< element << "'" << std::endl;
return; return;
}
// Get mode and check size // Get mode and check size
bool rect_mode = parts[0].find(',') != std::string::npos; bool rect_mode = parts[0].find(',') != std::string::npos;
@ -2714,35 +2654,25 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
void GUIFormSpecMenu::parseSetFocus(const std::string &element) void GUIFormSpecMenu::parseSetFocus(const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); std::vector<std::string> parts;
if (!precheckElement("set_focus", element, 2, 2, parts))
return;
if (parts.size() <= 2 ||
(parts.size() > 2 && m_formspec_version > FORMSPEC_API_VERSION))
{
if (m_is_form_regenerated) if (m_is_form_regenerated)
return; // Never focus on resizing return; // Never focus on resizing
bool force_focus = parts.size() >= 2 && is_yes(parts[1]); bool force_focus = parts.size() >= 2 && is_yes(parts[1]);
if (force_focus || m_text_dst->m_formname != m_last_formname) if (force_focus || m_text_dst->m_formname != m_last_formname)
setFocus(parts[0]); setFocus(parts[0]);
return;
}
errorstream << "Invalid set_focus element (" << parts.size() << "): '" << element
<< "'" << std::endl;
} }
void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element) void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(element, ';'); MY_CHECKCLIENT("model");
if (parts.size() < 5 || (parts.size() > 10 && std::vector<std::string> parts;
m_formspec_version <= FORMSPEC_API_VERSION)) { if (!precheckElement("model", element, 5, 10, parts))
errorstream << "Invalid model element (" << parts.size() << "): '" << element
<< "'" << std::endl;
return; return;
}
// Avoid length checks by resizing // Avoid length checks by resizing
if (parts.size() < 10) if (parts.size() < 10)

@ -279,6 +279,8 @@ protected:
v2s32 getElementBasePos(const std::vector<std::string> *v_pos); v2s32 getElementBasePos(const std::vector<std::string> *v_pos);
v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos); v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos);
v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom); v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
bool precheckElement(const std::string &name, const std::string &element,
size_t args_min, size_t args_max, std::vector<std::string> &parts);
std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type; std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type;
std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name; std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name;