|
|
@@ -8,6 +8,7 @@
|
|
|
#include <anki/misc/Common.h>
|
|
|
#include <anki/util/String.h>
|
|
|
#include <anki/util/DynamicArray.h>
|
|
|
+#include <anki/util/StringList.h>
|
|
|
#include <anki/Math.h>
|
|
|
#include <tinyxml2.h>
|
|
|
#if !ANKI_TINYXML2
|
|
|
@@ -57,26 +58,46 @@ public:
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- /// Return the text inside a tag
|
|
|
+ /// Return the text inside a tag. May return empty string.
|
|
|
ANKI_USE_RESULT Error getText(CString& out) const;
|
|
|
|
|
|
- /// Return the text inside as an int
|
|
|
- ANKI_USE_RESULT Error getI64(I64& out) const;
|
|
|
-
|
|
|
- /// Return the text inside as a float
|
|
|
- ANKI_USE_RESULT Error getF64(F64& out) const;
|
|
|
-
|
|
|
- /// Return the text inside as a float
|
|
|
- ANKI_USE_RESULT Error getF32(F32& out) const
|
|
|
+ /// Return the text inside as a number.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getNumber(T& out) const
|
|
|
{
|
|
|
- F64 outd;
|
|
|
- ANKI_CHECK(getF64(outd));
|
|
|
- out = outd;
|
|
|
+ ANKI_CHECK(check());
|
|
|
+
|
|
|
+ const char* txt = m_el->GetText();
|
|
|
+ if(txt != nullptr)
|
|
|
+ {
|
|
|
+ ANKI_CHECK(CString(txt).toNumber(out));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ANKI_MISC_LOGE("Failed to return number. Element: %s", m_el->Value());
|
|
|
+ return ErrorCode::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
return ErrorCode::NONE;
|
|
|
}
|
|
|
|
|
|
- /// Get a number of floats
|
|
|
- ANKI_USE_RESULT Error getFloats(DynamicArrayAuto<F64>& out) const;
|
|
|
+ /// Get a number of numbers.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getNumbers(DynamicArrayAuto<T>& out) const
|
|
|
+ {
|
|
|
+ CString txt;
|
|
|
+ ANKI_CHECK(getText(txt));
|
|
|
+
|
|
|
+ if(txt)
|
|
|
+ {
|
|
|
+ return parseNumbers(txt, out);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ out = DynamicArrayAuto<T>(m_alloc);
|
|
|
+ return ErrorCode::NONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/// Return the text inside as a Mat4
|
|
|
ANKI_USE_RESULT Error getMat4(Mat4& out) const;
|
|
|
@@ -106,11 +127,145 @@ public:
|
|
|
/// @note The sibling elements share the same name.
|
|
|
ANKI_USE_RESULT Error getSiblingElementsCount(U32& out) const;
|
|
|
|
|
|
+ /// @name Get attributes optional
|
|
|
+ /// @{
|
|
|
+
|
|
|
+ /// Get value of a string attribute. May return empty string.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ /// @param attribPresent True if the attribute exists. If it doesn't the @a out is undefined.
|
|
|
+ ANKI_USE_RESULT Error getAttributeTextOptional(const CString& name, CString& out, Bool& attribPresent) const;
|
|
|
+
|
|
|
+ /// Get the attribute's value as a series of numbers.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ /// @param attribPresent True if the attribute exists. If it doesn't the @a out is undefined.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getAttributeNumbersOptional(
|
|
|
+ const CString& name, DynamicArrayAuto<T>& out, Bool& attribPresent) const
|
|
|
+ {
|
|
|
+ CString txtVal;
|
|
|
+ ANKI_CHECK(getAttributeTextOptional(name, txtVal, attribPresent));
|
|
|
+
|
|
|
+ if(txtVal && attribPresent)
|
|
|
+ {
|
|
|
+ return parseNumbers(txtVal, out);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return ErrorCode::NONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get the attribute's value as a number.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ /// @param attribPresent True if the attribute exists. If it doesn't the @a out is undefined.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getAttributeNumberOptional(const CString& name, T& out, Bool& attribPresent) const
|
|
|
+ {
|
|
|
+ DynamicArrayAuto<T> arr(m_alloc);
|
|
|
+ ANKI_CHECK(getAttributeIntsOptional(name, arr, attribPresent));
|
|
|
+
|
|
|
+ if(attribPresent)
|
|
|
+ {
|
|
|
+ if(arr.getSize() != 1)
|
|
|
+ {
|
|
|
+ ANKI_MISC_LOGE("Expecting one element for attrib %s", &name[0]);
|
|
|
+ return ErrorCode::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ out = arr[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ return ErrorCode::NONE;
|
|
|
+ }
|
|
|
+ /// @}
|
|
|
+
|
|
|
+ /// @name Get attributes
|
|
|
+ /// @{
|
|
|
+
|
|
|
+ /// Get value of a string attribute. May return empty string.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ ANKI_USE_RESULT Error getAttributeText(const CString& name, CString& out) const
|
|
|
+ {
|
|
|
+ Bool found;
|
|
|
+ ANKI_CHECK(getAttributeTextOptional(name, out, found));
|
|
|
+ return throwAttribNotFoundError(name, found);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get the attribute's value as a series of numbers.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getAttributeNumbers(const CString& name, DynamicArrayAuto<T>& out) const
|
|
|
+ {
|
|
|
+ Bool found;
|
|
|
+ ANKI_CHECK(getAttributeNumbersOptional(name, out, found));
|
|
|
+ return throwAttribNotFoundError(name, found);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Get the attribute's value as a number.
|
|
|
+ /// @param name The name of the attribute.
|
|
|
+ /// @param out The value of the attribute.
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error getAttributeNumber(const CString& name, T& out) const
|
|
|
+ {
|
|
|
+ Bool found;
|
|
|
+ ANKI_CHECK(getAttributeNumberOptional(name, out, found));
|
|
|
+ return throwAttribNotFoundError(name, found);
|
|
|
+ }
|
|
|
+ /// @}
|
|
|
+
|
|
|
private:
|
|
|
const tinyxml2::XMLElement* m_el;
|
|
|
GenericMemoryPoolAllocator<U8> m_alloc;
|
|
|
|
|
|
ANKI_USE_RESULT Error check() const;
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ ANKI_USE_RESULT Error parseNumbers(CString txt, DynamicArrayAuto<T>& out) const
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(txt);
|
|
|
+ ANKI_ASSERT(m_el);
|
|
|
+
|
|
|
+ StringListAuto list(m_alloc);
|
|
|
+ list.splitString(txt, ' ');
|
|
|
+
|
|
|
+ out = DynamicArrayAuto<T>(m_alloc);
|
|
|
+ out.create(list.getSize());
|
|
|
+
|
|
|
+ Error err = ErrorCode::NONE;
|
|
|
+ auto it = list.getBegin();
|
|
|
+ auto end = list.getEnd();
|
|
|
+ U i = 0;
|
|
|
+ while(it != end && !err)
|
|
|
+ {
|
|
|
+ err = it->toNumber(out[i++]);
|
|
|
+ ++it;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(err)
|
|
|
+ {
|
|
|
+ ANKI_MISC_LOGE("Failed to parse floats. Element: %s", m_el->Value());
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ ANKI_USE_RESULT Error throwAttribNotFoundError(CString attrib, Bool found) const
|
|
|
+ {
|
|
|
+ if(!found)
|
|
|
+ {
|
|
|
+ ANKI_MISC_LOGE("Attribute not found %s", &attrib[0]);
|
|
|
+ return ErrorCode::USER_DATA;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return ErrorCode::NONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
/// XML document
|