Esempio n. 1
0
/*!
 * 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;
	}
}