in trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FormattedTextParser.java [69:317]
public void writeFormattedText(
FacesContext context,
String text) throws IOException
{
int length = text.length();
ArrayList<ElementInfo> elementStack =
new ArrayList<ElementInfo>(10);
// Constant for current parsing state
int state = _OUT_OF_ELEMENT;
ResponseWriter writer = context.getResponseWriter();
int i = 0;
while (i < length)
{
char c = text.charAt(i);
switch (state)
{
case _OUT_OF_ELEMENT:
// Start of an element tag:
if (c == '<')
{
// First, find out if we're starting a new
// element or closing an earlier one
boolean close = false;
if (((i + 1) < length) && (text.charAt(i + 1) == '/'))
{
close = true;
i++;
}
// Seek to the end of this element name
int endOfElementName = _getEndOfElementName(text, i + 1, length);
if (endOfElementName < 0)
{
i = length;
break;
}
// Retrieve the element name
String elementName = text.substring(i + 1, endOfElementName);
// Find out information about this element; in particular,
// is this an allowed element?
ElementInfo info = _elements.get(elementName);
// Allowed elements.
if (info != null)
{
if (close)
{
if (_popElement(context, elementStack, info))
{
// Render (only if "popping" found a match)
info.endElement(context);
}
// and skip to the end of the element
int endOfElement = text.indexOf('>', i);
if (endOfElement < 0)
{
_parseError("Unterminated element", i);
i = length;
break;
}
i = endOfElement + 1;
}
// Starting an allowed element
else
{
// Render and move to the start of the attributes
_pushElement(context, elementStack, info);
info.startElement(context);
state = (info.isEmptyElement()
? _IN_EMPTY_ELEMENT : _IN_ELEMENT);
i = endOfElementName;
}
}
// An unsupported element. Jump past its end, and output
// nothing.
else
{
int endOfElement = text.indexOf('>', i);
if (endOfElement < 0)
{
_parseError("Unterminated element", i);
i = length;
break;
}
i = endOfElement + 1;
}
}
// Not in an element; render the text
else
{
// An entity?
if (c == '&')
{
int endOfEntity = _getEndOfEntity(text, i, length);
// Couldn't find a semicolon; this probably wasn't
// intended as an entity. Just output the
// ampersand directly
if (endOfEntity < 0)
{
char[] chars = new char[1];
chars[0] = c;
writer.writeText(chars, 0, 1);
i++;
}
// It's an entity - output it.
else
{
c = _getEntity(text, i, endOfEntity);
if (c != 0)
{
char[] chars = new char[1];
chars[0] = c;
writer.writeText(chars, 0, 1);
}
i = endOfEntity + 1;
}
}
// Just write out the character
else
{
char[] chars = new char[1];
chars[0] = c;
writer.writeText(chars, 0, 1);
i++;
}
}
break;
case _IN_EMPTY_ELEMENT:
case _IN_ELEMENT:
// Inside an element; process attributes until
// the element ends.
if (c == '>')
{
// Ending an empty element - end it here.
if (state == _IN_EMPTY_ELEMENT)
{
ElementInfo info = _peekElement(elementStack);
info.endElement(context);
_popElement(context, elementStack, info);
}
state = _OUT_OF_ELEMENT;
i++;
}
else if (!Character.isWhitespace(c))
{
// Starting an attribute
int endOfAttributeName = _getEndOfAttributeName(text, i, length);
if (endOfAttributeName < 0)
{
_parseError("Unterminated attribute name", i);
i = length;
break;
}
String attributeName = text.substring(i, endOfAttributeName);
// An attribute with a value
if ('=' == text.charAt(endOfAttributeName))
{
if (endOfAttributeName + 1 >= length)
{
_parseError("Unterminated attribute value",
endOfAttributeName);
i = length;
break;
}
StringBuffer buffer = new StringBuffer();
int endOfAttributeValue =
_getAttributeValue(text,
endOfAttributeName + 1,
length,
buffer);
if (endOfAttributeValue < 0)
{
_parseError("Unterminated attribute value",
endOfAttributeName + 1);
i = length;
break;
}
ElementInfo info = _peekElement(elementStack);
// Output only the allowed attributes - CSS attributes only
// and <font>'s size attribute.
if ("class".equalsIgnoreCase(attributeName))
{
info.writeStyleClass(context, buffer.toString());
}
else if ("style".equalsIgnoreCase(attributeName))
{
info.writeInlineStyle(context, buffer.toString());
}
else if ("href".equalsIgnoreCase(attributeName))
{
info.writeHRef(context, buffer.toString());
}
else if ("size".equalsIgnoreCase(attributeName))
{
info.writeSize(context, buffer.toString());
}
i = endOfAttributeValue + 1;
}
// An empty attribute (no value) - treat as Boolean.TRUE
else
{
// =-=AEW We don't currently support any boolean attributes!
// out.writeAttribute(attributeName, Boolean.TRUE);
if ('>' == text.charAt(endOfAttributeName))
i = endOfAttributeName;
else
i = endOfAttributeName + 1;
}
}
else
{
// Whitespace in an element - just skip over it.
i++;
}
break;
}
}
// Close up any leftover elements
int size = elementStack.size() - 1;
while (size >= 0)
{
ElementInfo info = elementStack.get(size);
info.endElement(context);
// These _should_ all be elements that do not require being closed.
if (info.isCloseRequired())
_parseError("Unterminated element " + info.getName(), i);
--size;
}
}