svg_loader: ommiting xml entities in the svg file (#278)

SVG files created using 'sketch' may contain xml entities,
which are not understandable by the svg loader.
For now only '"' is ommited.
This commit is contained in:
Mira Grudzinska 2021-03-23 01:22:46 +01:00 committed by GitHub
parent 79f1ba8516
commit 234a9b2f93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 13 deletions

View file

@ -89,6 +89,69 @@ static const char* _simpleXmlUnskipWhiteSpace(const char* itr, const char* itrSt
}
static const char* _simpleXmlSkipXmlEntities(const char* itr, const char* itrEnd)
{
auto p = itr;
while (*itr == '&' && itr < itrEnd) {
for (int i = 0; i < NUMBER_OF_XML_ENTITIES; ++i) {
if (strncmp(itr, xmlEntity[i], xmlEntityLength[i]) == 0) {
itr += xmlEntityLength[i];
break;
}
}
if (itr == p) break;
p = itr;
}
return itr;
}
static const char* _simpleXmlUnskipXmlEntities(const char* itr, const char* itrStart)
{
auto p = itr;
while (*(itr - 1) == ';' && itr > itrStart) {
for (int i = 0; i < NUMBER_OF_XML_ENTITIES; ++i) {
if (itr - xmlEntityLength[i] > itrStart &&
strncmp(itr - xmlEntityLength[i], xmlEntity[i], xmlEntityLength[i]) == 0) {
itr -= xmlEntityLength[i];
break;
}
}
if (itr == p) break;
p = itr;
}
return itr;
}
static const char* _skipWhiteSpacesAndXmlEntities(const char* itr, const char* itrEnd)
{
itr = _simpleXmlSkipWhiteSpace(itr, itrEnd);
auto p = itr;
while (true) {
if (p != (itr = _simpleXmlSkipXmlEntities(itr, itrEnd))) p = itr;
else break;
if (p != (itr = _simpleXmlSkipWhiteSpace(itr, itrEnd))) p = itr;
else break;
}
return itr;
}
static const char* _unskipWhiteSpacesAndXmlEntities(const char* itr, const char* itrStart)
{
itr = _simpleXmlUnskipWhiteSpace(itr, itrStart);
auto p = itr;
while (true) {
if (p != (itr = _simpleXmlUnskipXmlEntities(itr, itrStart))) p = itr;
else break;
if (p != (itr = _simpleXmlUnskipWhiteSpace(itr, itrStart))) p = itr;
else break;
}
return itr;
}
static const char* _simpleXmlFindStartTag(const char* itr, const char* itrEnd)
{
return (const char*)memchr(itr, '<', itrEnd - itr);
@ -144,7 +207,7 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
if (!buf || !func) return false;
while (itr < itrEnd) {
const char* p = _simpleXmlSkipWhiteSpace(itr, itrEnd);
const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd);
const char *key, *keyEnd, *value, *valueEnd;
char* tval;
@ -163,9 +226,9 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
if (!value) return false;
value++;
}
for (; value < itrEnd; value++) {
if (!isspace((unsigned char)*value)) break;
}
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key);
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
if (value == itrEnd) return false;
if ((*value == '"') || (*value == '\'')) {
@ -176,20 +239,28 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd);
}
itr = valueEnd + 1;
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
valueEnd = _unskipWhiteSpacesAndXmlEntities(valueEnd, value);
memcpy(tmpBuf, key, keyEnd - key);
tmpBuf[keyEnd - key] = '\0';
tval = tmpBuf + (keyEnd - key) + 1;
memcpy(tval, value, valueEnd - value);
tval[valueEnd - value] = '\0';
int i = 0;
while (value < valueEnd) {
value = _simpleXmlSkipXmlEntities(value, valueEnd);
tval[i++] = *value;
value++;
}
tval[i] = '\0';
#ifdef THORVG_LOG_ENABLED
if (!func((void*)data, tmpBuf, tval)) printf("SVG: Unsupported attributes used [Elements type: %s][Attribute: %s]\n", simpleXmlNodeTypeToString(((SvgLoaderData*)data)->svgParse->node->type).c_str(), tmpBuf);
#else
func((void*)data, tmpBuf, tval);
#endif
itr = valueEnd + 1;
}
return true;
}
@ -290,8 +361,8 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
}
if ((strip) && (type != SimpleXMLType::Error) && (type != SimpleXMLType::CData)) {
start = _simpleXmlSkipWhiteSpace(start, end);
end = _simpleXmlUnskipWhiteSpace(end, start + 1);
start = _skipWhiteSpacesAndXmlEntities(start, end);
end = _unskipWhiteSpacesAndXmlEntities(end, start);
}
CB(type, start, end);
@ -307,7 +378,8 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
const char *p, *end;
if (strip) {
p = _simpleXmlSkipWhiteSpace(itr, itrEnd);
p = itr;
p = _skipWhiteSpacesAndXmlEntities(p, itrEnd);
if (p) {
CB(SimpleXMLType::Ignored, itr, p);
itr = p;
@ -318,7 +390,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
if (!p) p = itrEnd;
end = p;
if (strip) end = _simpleXmlUnskipWhiteSpace(end, itr);
if (strip) end = _unskipWhiteSpacesAndXmlEntities(end, itr);
if (itr != end) CB(SimpleXMLType::Data, itr, end);
@ -393,7 +465,7 @@ const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength)
//User skip tagname and already gave it the attributes.
if (*itr == '=') return buf;
} else {
itr = _simpleXmlSkipWhiteSpace(itr + 1, itrEnd);
itr = _simpleXmlUnskipXmlEntities(itr, buf);
if (itr == itrEnd) return nullptr;
return itr;
}

View file

@ -25,6 +25,10 @@
#include "tvgSvgLoaderCommon.h"
#define NUMBER_OF_XML_ENTITIES 8
const char* const xmlEntity[] = {"&quot;", "&nbsp;", "&apos;", "&amp;", "&lt;", "&gt;", "&#035;", "&#039;"};
const int xmlEntityLength[] = {6, 6, 6, 5, 4, 4, 6, 6};
enum class SimpleXMLType
{
Open = 0, //!< \<tag attribute="value"\>