void CModelReaderNode093_Object::OnAttribute(_In_z_ const nfWChar * pAttributeName, _In_z_ const nfWChar * pAttributeValue)
{
    __NMRASSERT(pAttributeName);
    __NMRASSERT(pAttributeValue);

    if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_OBJECT_ID) == 0) {
        if (m_nID != 0)
            throw CNMRException(NMR_ERROR_DUPLICATEOBJECTID);

        // Convert to integer and make a input and range check!
        m_nID = fnWStringToUint32(pAttributeValue);

        // Increase ID to avoid 0 (was allowed for 0.9.3)
        m_nID++;
    }

    if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_OBJECT_TYPE) == 0) {
        if (m_bHasType)
            throw CNMRException(NMR_ERROR_DUPLICATEOBJECTTYPE);

        // Convert to integer and make a input and range check!
        std::wstring sString(pAttributeValue);
        m_sType = sString;
        m_bHasType = true;
    }

    if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_OBJECT_NAME) == 0) {
        std::wstring sValue(pAttributeValue);
        m_sName = sValue;
    }

    if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_COLORID) == 0) {

        nfInt32 nValue = fnWStringToInt32(pAttributeValue);
        if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX)) {
            m_nColorID = nValue + 1;
        }
    }

    if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_MATERIALID) == 0) {
        nfInt32 nValue = fnWStringToInt32(pAttributeValue);
        if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
            m_nMaterialID = nValue + 1;
    }


}
	void CModelReaderNode093_Color::parseColor()
	{
		m_cColor = 0;

		try {
			if (m_sColorString.length() > 0) {
				nfWChar bFirstChar = m_sColorString[0];
				if (bFirstChar == L'#') {
					if (fnWStringToSRGBColor(m_sColorString.c_str(), m_cColor)) {
						return;
					}
				}

				if (bFirstChar == L's') {
					std::wstring sSubStr = m_sColorString.substr(0, 5);
					if (sSubStr == L"scRGB") {
						// parse scRGB String
						throw CNMRException(NMR_ERROR_NOTIMPLEMENTED);
					}
				}

				if (bFirstChar == L't') {
					std::wstring sSubStr = m_sColorString.substr(0, 4);
					if (sSubStr == L"tex(") {
						// parse Texture String

						if (m_sColorString.length() > 4) {
							std::wstring sTexID = m_sColorString.substr(4, m_sColorString.length() - sSubStr.length() - 1);
							nfInt32 nValue = fnWStringToInt32(sTexID.c_str());
							if ((nValue < 0) || (nValue >= XML_3MF_MAXRESOURCEINDEX))
								throw CNMRException(NMR_ERROR_INVALIDTEXTUREREFERENCE);

							m_nTextureID = nValue + 1;

						}
						else {
							throw CNMRException(NMR_ERROR_INVALIDTEXTUREREFERENCE);
						}
					}
				}

				if (bFirstChar == L'C') {
					std::wstring sSubStr4 = m_sColorString.substr(0, 4);
					if (sSubStr4 == L"CMYK") {
						throw CNMRException(NMR_ERROR_NOTSUPPORTINGLEGACYCMYK);
					}
				}

			}

			throw CNMRException(NMR_ERROR_INVALIDVALUEINCOLORSTRING);
		}
		catch (CNMRException & Exception) {
			m_pWarnings->addException(Exception, mrwMissingMandatoryValue);
		}

	}
	void CModelReaderNode_BeamLattice1702_Beam::OnAttribute(_In_z_ const nfWChar * pAttributeName, _In_z_ const nfWChar * pAttributeValue)
	{
		__NMRASSERT(pAttributeName);
		__NMRASSERT(pAttributeValue);

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_V1) == 0) {
			nfInt32 nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex1 = nValue;
		}
		else if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_V2) == 0) {
			nfInt32 nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex2 = nValue;
		}
		else if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_R1) == 0) {
			nfFloat fValue = fnWStringToFloat(pAttributeValue);
			if ((fValue >= 0) && (fValue < XML_3MF_MAXIMUMBEAMRADIUSVALUE)) {
				m_dRadius1 = fValue;
				m_bHasRadius1 = true;
			}
		}
		else if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_R2) == 0) {
			nfFloat fValue = fnWStringToFloat(pAttributeValue);
			if ((fValue >= 0) && (fValue < XML_3MF_MAXIMUMBEAMRADIUSVALUE)) {
				m_dRadius2 = fValue;
				m_bHasRadius2 = true;
			}
		}
		else if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_CAP1) == 0) {
			m_bHasCap1 = true;
			m_eCapMode1 = stringToCapMode(pAttributeValue);
		}
		else if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_BEAMLATTICE_CAP2) == 0) {
			m_bHasCap2 = true;
			m_eCapMode2 = stringToCapMode(pAttributeValue);
		}
		else
			m_pWarnings->addException(CNMRException(NMR_ERROR_BEAMLATTICEINVALIDATTRIBUTE), mrwInvalidOptionalValue);
	}
	void CModelReaderNode100_Triangle::OnAttribute(_In_z_ const nfWChar * pAttributeName, _In_z_ const nfWChar * pAttributeValue)
	{
		__NMRASSERT(pAttributeName);
		__NMRASSERT(pAttributeValue);
		nfInt32 nValue;

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V1) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex1 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V2) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex2 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V3) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex3 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_PID) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEID))
				m_nPropertyID = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_P1) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nPropertyIndex1 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_P2) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nPropertyIndex2 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_P3) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nPropertyIndex3 = nValue;
		}
	}
	void CModelReaderNode093_Triangle::OnAttribute(_In_z_ const nfWChar * pAttributeName, _In_z_ const nfWChar * pAttributeValue)
	{
		__NMRASSERT(pAttributeName);
		__NMRASSERT(pAttributeValue);
		nfInt32 nValue;

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V1) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex1 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V2) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex2 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_V3) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nIndex3 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_CV1) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nTextureIndex1 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_CV2) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nTextureIndex2 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_CV3) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nTextureIndex3 = nValue;
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_COLORID) == 0) {
			std::wstring sValue(pAttributeValue);
			std::wstring sSubStr = sValue.substr(0, 4);
			if (sSubStr == L"tex(") {
				if (sValue.length() > 4) {
					std::wstring sTexID = sValue.substr(4, sValue.length() - sSubStr.length() - 1);
					nfInt32 nValue = fnWStringToInt32(sTexID.c_str());
					if ((nValue < 0) || (nValue >= XML_3MF_MAXRESOURCEINDEX))
						throw CNMRException(NMR_ERROR_INVALIDTEXTUREREFERENCE);

					m_nTextureID = nValue + 1;

				}
				else {
					throw CNMRException(NMR_ERROR_INVALIDTEXTUREREFERENCE);
				}

			}
			else {
				const wchar_t * pCommaValue = wcschr(pAttributeValue, L',');

				// Check, if we have a single value
				if (pCommaValue == nullptr) {

					nValue = fnWStringToInt32(pAttributeValue);
					if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX)) {
						m_nColorID1 = nValue + 1;
						m_nColorID2 = nValue + 1;
						m_nColorID3 = nValue + 1;
					}
				}
				else {
					// Check, if we have a color triplet
					nfInt32 nColorID1 = -1;
					nfInt32 nColorID2 = -1;
					nfInt32 nColorID3 = -1;

					fnStringToCommaSeparatedIntegerTriplet(pAttributeValue, nColorID1, nColorID2, nColorID3);

					if ((nColorID1 >= 0) && (nColorID1 < XML_3MF_MAXRESOURCEINDEX))
						m_nColorID1 = nColorID1 + 1;
					if ((nColorID2 >= 0) && (nColorID2 < XML_3MF_MAXRESOURCEINDEX))
						m_nColorID2 = nColorID2 + 1;
					if ((nColorID3 >= 0) && (nColorID3 < XML_3MF_MAXRESOURCEINDEX))
						m_nColorID3 = nColorID3 + 1;
				}
			}
		}

		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_TRIANGLE_MATERIALID) == 0) {
			nValue = fnWStringToInt32(pAttributeValue);
			if ((nValue >= 0) && (nValue < XML_3MF_MAXRESOURCEINDEX))
				m_nMaterialID = nValue + 1;
		}

	}
	void CModelReaderNode_Slices1507_Segment::OnAttribute(_In_z_ const nfWChar * pAttributeName, _In_z_ const nfWChar * pAttributeValue) {
		if (wcscmp(pAttributeName, XML_3MF_ATTRIBUTE_SLICESEGMENT_V2) == 0) {
			m_pSlice->addPolygonIndex(m_PolygonIndex, fnWStringToInt32(pAttributeValue));
		}
	}