/*! * Sets given attribute in this PP_AttrProp bundle. * Deals correctly with setting the PT_PROPS_ATTRIBUTE_NAME property: * intercepts this call and appends properties instead. * * Because all mutations of attributes go through here, it is always the * case that the props attribute is correctly handled. */ bool PP_AttrProp::setAttribute(const gchar * szName, const gchar * szValue) { // TODO when this assert fails, switch this file to use UT_XML_ version of str*() functions. UT_return_val_if_fail (sizeof(char)==sizeof(gchar), false); if (0 == strcmp(szName, PT_PROPS_ATTRIBUTE_NAME) && *szValue) // PROPS -- cut value up into properties { char * pOrig = NULL; if (!(pOrig = g_strdup(szValue))) { UT_DEBUGMSG(("setAttribute: g_strdup() failed on [%s]\n",szValue)); return false; } // This function parses out CSS properties, separated by semicolons. char *z = pOrig; int bDone = 0; while (!bDone) { // p will point to the property name. q will be the property value. char *p = z; char *q = p; // skip the whitespace before the property name while (isspace(*p)) p++; // skip to the colon to find the value while (*q && (*q != ':')) q++; // if there was no colon, this is invalid if (!*q) { g_free(pOrig); UT_DEBUGMSG(("props: %s\n", szValue)); return false; } // zero-out the colon, thus separating into two strings. *q = 0; q++; // now, search ahead for the next semicolon, and separate this property from the next z = q; while (*z && (*z != ';')) z++; if (*z == ';') { *z = 0; z++; } else { bDone = 1; } // skip the whitespace before the property value while ((*q > 0) && isspace(*q)) q++; setProperty(p, q); } g_free(pOrig); return true; } else if (0 == strcmp(szName, PT_XID_ATTRIBUTE_NAME) && *szValue) { // XID is a unique id for the xml element / PT frag. Its function is to facilitate // comparing/merging documents and we do not want it in the AP return true; } else // not "PROPS" -- add to attribute list { UT_UTF8String url; if (szValue && *szValue && (0 == strcmp(szName, "xlink:href") || 0 == strcmp(szName, "href"))) { url = szValue; url.decodeURL(); szValue = url.utf8_str(); } if (!m_pAttributes) { m_pAttributes = new UT_GenericStringMap<gchar*>(5); if (!m_pAttributes) { UT_DEBUGMSG(("setAttribute: could not allocate hash table.\n")); return false; } } // make sure we store attribute names in lowercase UT_ASSERT_HARMLESS(sizeof(char) == sizeof(gchar)); char * copy = g_ascii_strdown(szName, -1); char * szDupValue = szValue ? g_strdup(szValue) : NULL; // get rid of any illegal chars we might have been given if(!UT_isValidXML(copy)) UT_validXML(copy); if(!UT_isValidXML(szDupValue)) UT_validXML(szDupValue); const char * pEntry = m_pAttributes->pick(copy); if(pEntry) { // attribute exists, replace it FREEP(pEntry); m_pAttributes->set(copy, szDupValue); } else { bool bRet = m_pAttributes->insert(copy, szDupValue); UT_ASSERT_HARMLESS( bRet ); if(!bRet) { FREEP(szDupValue); } } FREEP(copy); return true; } }