Skip to content

Instantly share code, notes, and snippets.

@isapir
Created August 24, 2012 01:50
Show Gist options
  • Save isapir/3444631 to your computer and use it in GitHub Desktop.
Save isapir/3444631 to your computer and use it in GitHub Desktop.
a class that can extends CFMLWriterWhiteSpace.java to allow for pre-formatted text in PRE tags and TEXTAREAs
import java.io.IOException;
import java.io.PrintStream; // TODO: this is for test purpose only; remove it when ridding of this.out
/**
* this class that can extends CFMLWriterWhiteSpace.java to allow for pre-formatted text in PRE tags and TEXTAREAs
*/
public class CFMLWriterWhiteSpacePre extends javax.servlet.jsp.JspWriter {
/* snippet begin */
public static final char CHAR_NL = '\n';
public static final char CHAR_SP = ' ';
public static final char CHAR_LT = '<';
private char lastChar = 0;
private int preDepth = 0;
private int txtDepth = 0;
private boolean doChangeWsToSpace = true; // can help fight XSS attacks with characters like Vertical Tab
private StringBuilder sb = new StringBuilder();
/**
* prints the characters from the buffer and resets it
*
* TODO: make sure that printBuffer() is called at the end of the stream in case we have some characters there! (flush() ?)
*/
private synchronized void printBuffer() { // TODO: not sure if synchronized is needed here?
int len = sb.length();
char[] chars = new char[ len ];
sb.getChars( 0, len, chars, 0 );
sb.setLength( 0 );
out.print( chars ); // TODO: change-to: super.write( chars, 0, chars.length );
}
/**
* checks if a character is part of an open html tag or close html tag, and if so adds it to the buffer, otherwise returns false.
*
* @param c
* @return true if the char was added to the buffer, false otherwise
*/
boolean addToBuffer( char c ) {
int len = sb.length();
if ( len == 0 && c != CHAR_LT )
return false; // buffer must starts with '<'
sb.append( c ); // if we reached this point then we will return true
if ( ++len > 5 ) { // increment len as it was sampled before we appended c
String substr = sb.substring( 1, 6 ); // we know that the 1st char is < so no need to test it
if ( substr.equalsIgnoreCase( "/pre>" ) ) {
if ( --preDepth < 0 ) preDepth = 0; // decrement and ensure non-negative
} else if ( substr.equalsIgnoreCase( "/text" ) ) {
if ( --txtDepth < 0 ) txtDepth = 0; // decrement and ensure non-negative
}
printBuffer();
} else if ( len == 5 ) {
String substr = sb.substring( 1, 5 );
if ( substr.equalsIgnoreCase( "pre>" ) ) {
preDepth++;
} else if ( substr.equalsIgnoreCase( "text" ) ) {
txtDepth++;
}
}
return true;
}
/**
* sends a character to output stream if it is not a consecutive white-space unless we're inside a PRE or TEXTAREA tag.
*
* @param c
* @throws IOException
*/
@Override
public void print( char c ) throws IOException {
boolean isWS = Character.isWhitespace( c );
if ( isWS && sb.length() > 0 )
printBuffer(); // buffer should never contain WS so no need to call addToBuffer()
if ( isWS || !addToBuffer( c ) ) {
if ( preDepth + txtDepth == 0 ) { // we're not in PRE nor TEXTAREA; suppress whitespace
if ( isWS ) { // this char is WS
if ( lastChar == CHAR_NL ) // lastChar was NL; discard this WS char
return;
if ( c != CHAR_NL ) { // this WS char is not NL
if ( Character.isWhitespace( lastChar ) )
return; // lastChar was WS but Not NL; discard this WS char
if ( doChangeWsToSpace )
c = CHAR_SP; // this char is WS and not NL; change it to a regular space
}
}
}
lastChar = c; // remember c as lastChar and write it to output stream
out.print( c ); // TODO: change-to: call super.print( c );
}
}
/* snippet end */
/* test objects and methods below */
PrintStream out = System.out; // for testing
public CFMLWriterWhiteSpacePre( int bufferSize, boolean autoFlush ) {
super( bufferSize, autoFlush );
}
@Override
public void print(String string) throws IOException {
char[] chars = string.toCharArray();
for ( char c : chars ) {
print( c );
}
}
public static void main(String[] args) throws IOException {
CFMLWriterWhiteSpacePre w = new CFMLWriterWhiteSpacePre( 256, true );
String[] strings = {
"this is a test without \t any \b tags."
, "this one is another\t\t\t\t\b \b \t string with no TAGs At All!"
, "this <b>one</b> HAS\t\t\t\t\b \b <h1>Some TAGs</h1> but nothing pre-formatted "
, "\n\n\n\n\t\t\t\n\n\n this String should be preceded by a single NL only. did it work? "
, "\t\t\t \n\n\n<PRE> S O M E\r\n\r\n\t\tP R E \r\n\r\n\t T E X T</PRE> and now outside the PRE..."
, " and this is the\r\n\tlast\t\t\t line."
};
StringBuilder sb = new StringBuilder();
for ( String s : strings ) {
if ( s.contains( "<PRE>" ) )
System.out.println("");
System.out.println( "[" + s + "]" );
w.print( s );
w.print( '\n' );
sb.append(s).append("\r\n").append("\r\n").append("\r\n").append("\r\n").append("\r\n");
}
String s = sb.toString();
System.out.println( "[" + s + "]" );
w.print( s );
w.print( '\n' );
}
/* JspWriter unsupported methods below */
@Override
public void newLine() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(boolean bln) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(int i) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(long l) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(float f) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(double d) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(char[] chars) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void print(Object o) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(boolean bln) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(char c) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(int i) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(long l) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(float f) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(double d) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(char[] chars) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(String string) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void println(Object o) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void clear() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void clearBuffer() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void close() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getRemaining() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment