/* * Copyright (C) 2000 - 2010 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbluedragon.org/ */ package com.naryx.tagfusion.cfm.parser; /** * This class filters out strings containing pound signs replacing them with * concatenation. * * Also removes the quotes from a string with only one */ import java.io.CharArrayWriter; import java.io.FilterReader; import java.io.IOException; import java.io.Reader; public class poundSignFilterStream extends FilterReader { char[] buffer = null; int bufferAt; int nextChar; boolean temp = false; int added; // keeps a count of the adjustment in length of the input vs output private boolean isClosed; public poundSignFilterStream(Reader _in) throws IOException { super( _in ); added = 0; readChar(); } synchronized public int read() throws IOException { // if the buffer is empty then if ( buffer == null ) { int returnChar; // if it's the start of a comment then read it into the buffer if ( nextChar == '/' ) { readChar(); if ( nextChar == '*' ) { buffer = readComment(); bufferAt = 0; } else if ( nextChar == '/' ) { buffer = readLineComment(); bufferAt = 0; } returnChar = '/'; // in all cases // if it's the start of a string then read the string into the buffer } else if ( nextChar == '"' || nextChar == '\'' ) { buffer = readString( true ); bufferAt = 1; returnChar = buffer[0]; if ( buffer.length == 1 ) buffer = null; } else { // else return the next char in the stream returnChar = nextChar; readChar(); } return returnChar; } else { /* buffer isn't empty so return next char from it */ int bufferChar = buffer[bufferAt]; bufferAt++; if ( bufferAt >= buffer.length ) buffer = null; return bufferChar; } } synchronized public int read( char[] cbuf, int off, int len ) throws IOException { int offset = off; int actualLen = 0; int nextChar = -1;// = read(); // note that read() is used as opposed to readChar() so that the # filtering // is performed at that level while ( actualLen < len && ( ( nextChar = read() ) != -1 ) ) { cbuf[offset] = (char) nextChar; actualLen++; offset++; } if ( nextChar == -1 && actualLen == 0 ) { return -1; } return actualLen; } /** * reads in the whole string from the input stream and does the following * before putting it in the buffer: - removes escaped single and double * quotes, and pound signs - replaces embedded pound sign expression within * the string with a string concatentation with the function/variable * * @param _withinExpression * if true then this indicates that the string is within an * expression so in the case "#poundsignexpr#", it will be reduced to * poundsignexpr as opposed to #poundsignexpr# as it would do * normally */ private char[] readString( boolean _withinExpression ) throws IOException { CharArrayWriter cout = new CharArrayWriter(); // might want to share this int endMarker = nextChar; cout.write( endMarker ); // write the " or ' surrounding the string readChar(); while ( nextChar != -1 ) { // if next character is start of a pound sign expression if ( nextChar == '#' ) { readChar(); // skip the pound sign // is it an escape char if ( nextChar == '#' ) { // escape it - i.e. don't add it onto the stream added--; cout.write( '#' ); readChar(); continue; } else { // # followed by non-# cout.write( endMarker ); cout.write( '&' ); // instead of the pound sign // copy these and write them to a new buffer with pound signs if the // next char is // a # and the char after that is a endMarker and the one after that // isn't an end marker CharArrayWriter expression = new CharArrayWriter(); while ( nextChar != '#' && nextChar != -1 ) { if ( nextChar == '\'' || nextChar == '"' ) { expression.write( readString( true ) ); } else { expression.write( nextChar ); readChar(); } } // now add the appropriate &" or whatever if ( nextChar == '#' ) { readChar(); // skip it if ( nextChar != endMarker ) { expression.writeTo( cout ); cout.write( '&' ); cout.write( endMarker ); added += 2; } else { readChar(); if ( nextChar != endMarker ) { if ( cout.size() == 3 ) { if ( !_withinExpression ) { cout.reset(); cout.write( '#' ); expression.writeTo( cout ); cout.write( '#' ); added++; return cout.toCharArray(); } else { // nextChar != endMarker && cout.size() == 3 && // withinExpression cout.reset(); expression.writeTo( cout ); added -= 4; return cout.toCharArray(); } } else { // nextChar != endMarker // end of string found added--; expression.writeTo( cout ); return cout.toCharArray(); } } else { expression.writeTo( cout ); cout.write( '&' ); cout.write( endMarker ); cout.write( endMarker ); // want to write the escaped end marker // here cout.write( endMarker ); // else won't be escaped properly if // allow it to pass thru added += 2; readChar(); } } } else { // throw an exception throw new poundSignFilterStreamException( "Invalid string expression - unclosed '#' expression" ); } } // else if reached endmarker - could be quote or double quote } else if ( nextChar == endMarker ) { readChar(); // is it an escape char; if so carry on if ( nextChar == endMarker ) { cout.write( endMarker ); cout.write( endMarker ); readChar(); } else { // else return the read string cout.write( endMarker ); return cout.toCharArray(); } // else, just a regular char; add it to the string being read } else { cout.write( nextChar ); readChar(); } } throw new IOException( "Unclosed string expression - missing " + endMarker + "." ); } public void close() throws IOException { super.close(); this.isClosed = true; } private int readChar() throws IOException { if ( this.isClosed ) { return -1; } nextChar = in.read(); return nextChar; } private char[] readComment() throws IOException { CharArrayWriter cout = new CharArrayWriter(); boolean endComment = false; cout.write( '*' ); readChar(); // read in the '*' while ( !endComment && nextChar != -1 ) { cout.write( nextChar ); if ( nextChar == '*' ) { readChar(); if ( nextChar == '/' ) { cout.write( '/' ); readChar(); endComment = true; } } else { readChar(); } } return cout.toCharArray(); } private char[] readLineComment() throws IOException { CharArrayWriter cout = new CharArrayWriter(); while ( nextChar != '\r' && nextChar != '\n' && nextChar != -1 ) { cout.write( nextChar ); readChar(); } return cout.toCharArray(); } public int getAdded() { return added; } }