/* * Copyright (C) 2000-2015 aw2.0 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.openbd.org/ * $Id: cfParseTag.java 2513 2015-02-13 00:24:49Z alan $ */ package com.naryx.tagfusion.cfm.tag; import java.io.BufferedReader; import java.io.CharArrayReader; import java.io.CharArrayWriter; import java.io.IOException; import java.io.StringReader; import java.util.Arrays; import java.util.List; import java.util.Map; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.NoViableAltException; import org.antlr.runtime.ParserRuleReturnScope; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.CommonTreeNodeStream; import com.nary.util.FastMap; import com.naryx.tagfusion.cfm.engine.catchDataFactory; import com.naryx.tagfusion.cfm.engine.cfEngine; import com.naryx.tagfusion.cfm.engine.cfOutputFilter; import com.naryx.tagfusion.cfm.engine.cfmBadFileException; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; import com.naryx.tagfusion.cfm.file.cfmlFileCache; import com.naryx.tagfusion.cfm.file.sourceReader; import com.naryx.tagfusion.cfm.parser.ANTLRNoCaseReaderStream; import com.naryx.tagfusion.cfm.parser.CFMLLexer; import com.naryx.tagfusion.cfm.parser.CFMLParser; import com.naryx.tagfusion.cfm.parser.CFMLTree; import com.naryx.tagfusion.cfm.parser.ParseException; import com.naryx.tagfusion.cfm.parser.poundSignFilterStream; import com.naryx.tagfusion.cfm.parser.poundSignFilterStreamException; import com.naryx.tagfusion.cfm.parser.script.CFScriptStatement; public class cfParseTag extends Object { public static int TAG_END_MARKER = 62; // '>' public static int TAG_START_MARKER = 60; // '<' public static int CHAR_SPACE = 32; // ' ' public static int CHAR_HYPEN = 45; // '-' public static int CHAR_TAB = 9; // '\t' public static int CHAR_LINEFEED = 10; // '\n' public static int CHAR_CARRIAGERETURN = 13; // '\r' public static int CHAR_FORWARDSLASH = 47; // '/' public static int CHAR_SINGLEQUOTE = 39; // '\'' public static int CHAR_DOUBLEQUOTE = 34; // '"' public static int CHAR_HASH = 35; // '#' public static int CHAR_OPEN_PAREN = 40; // '(' public static int CHAR_CLOSE_PAREN = 41; // ')' public static int CHAR_OPEN_BRACKET = 91; // '[' public static int CHAR_CLOSE_BRACKET = 93; // '[' public static int CHAR_EQUAL = 61; // '=' public static int CHAR_PERCENT = 37; // '%' private static char[] matchStart = new char[] { '<', '!', '-', '-', '-' }; private static char[] matchEnd = new char[] { '-', '-', '-', '>' }; private cfTag tagClass; private Map<String, String> importedMappings; public cfParseTag(cfTag tag) { tagClass = tag; importedMappings = new FastMap<String, String>(10); } private cfParseTag(cfTag tag, Map<String, String> _imported) { tagClass = tag; importedMappings = _imported; } public void readTag(tagReader inFile) throws IOException, cfmRunTimeException { readTag(inFile, null); } // read in all the tags from the file represented by tagReader private void readTag(tagReader inFile, String _endTagMarker) throws IOException, cfmBadFileException { CharArrayWriter tagBuffer = new CharArrayWriter(); // Read the tag boolean bReadingTag = false; StringBuilder tag = null; StringBuilder tagname = null; String tagElement = ""; int character = -1, lastcharactor = -1; boolean embeddedSigns = doesTagHaveEmbeddedPoundSigns(); while ((character = inFile.read()) != -1) { if (!bReadingTag && character == TAG_START_MARKER) { tag = new StringBuilder(32); tagname = new StringBuilder(8); bReadingTag = true; tag.append((char) character); inFile.mark(); } else if (bReadingTag) { tag.append((char) character); // Need to determine the tag name, and discover if we support this tag or not if (tag.length() > 0 && character == TAG_START_MARKER) { for (int x = 0; x < tag.length() - 1; x++) tagBuffer.write(tag.charAt(x)); tag = new StringBuilder(32); tagname = new StringBuilder(8); bReadingTag = true; tag.append((char) character); inFile.mark(); continue; } // <%= in a cfoutput block now #len(name)# %> if ( tag.length() == 3 && tag.charAt(1) == CHAR_PERCENT && tag.charAt(2) == CHAR_EQUAL && cfEngine.isCFOutputShorthand() ){ cfTag tg = createCFOutputRails(inFile, tagBuffer ); tg.posColumn = inFile.curColumn; tg.posLine = inFile.curLine; tg.setParentTag(this.tagClass); inFile.pushStartTag(tg); new cfParseTag(tg, importedMappings).readTag(inFile, tg.getEndMarker()); inFile.popEndTag(tg); tg.posEndColumn = inFile.curColumn; tg.posEndLine = inFile.curLine; bReadingTag = false; continue; } if (!isTagNameTerminatingChar(character) && (character != TAG_END_MARKER)) { tagname.append((char) character); // Is this tag a comment tag? If so then lets read if ((tagname.length() > 3) && (tagname.toString().indexOf("!---") != -1) && !(tagClass instanceof ContentTypeStaticInterface)) { /* We need to record the line */ int commentLine = readCommentTag(inFile); if (commentLine > 0) { tagClass.commentList.add(new Integer(commentLine)); tagBuffer.write(cfTag.COMMENT_MARKER); } bReadingTag = false; } continue; } else if ((tagname.length() > 0) && (isTagNameTerminatingChar(character) || (character == TAG_END_MARKER))) { // check for <cfreturn/> or <cfbreak/> syntax (XML-compliant closing with no attributes) if ((character == TAG_END_MARKER) && (tagname.charAt(tagname.length() - 1) == CHAR_FORWARDSLASH)) { tagname = tagname.deleteCharAt(tagname.length() - 1); if (tagname.length() == 0) { // tag is just </> so no need to look at the tagname any further continue; } } if (!isTagSupported(tagname.toString().toUpperCase()) || (tagClass instanceof ContentTypeStaticInterface)) { // read whitespace so we support </cfoutput > if (tagname.charAt(0) == '/' && Character.isWhitespace((char) character)) { do { character = inFile.read(); } while (character != -1 && Character.isWhitespace((char) character)); } // So the tag isn't supported, so lets check to see if its an ending tag if (character == TAG_END_MARKER && _endTagMarker != null && foundTag(_endTagMarker, tag.toString())) { inFile.popEndTag(tagClass); break; } else if ((character == TAG_END_MARKER) && checkEndTag(tag.toString()) && !(tagClass instanceof ContentTypeStaticInterface)) { inFile.addException(catchDataFactory.noStartTagException(tag.toString(), inFile.curLine, inFile.curColumn - tag.length())); continue; } else if ( (character == TAG_END_MARKER) && tag.toString().equalsIgnoreCase("<NOCFML>") ){ // Skip to the end of this tag; and capture all the tags, including CFML tags int start = inFile.currentIndx; int endNoCfml = inFile.nextIndexOf("</NOCFML>", start ); if (endNoCfml > 0) { tagBuffer.write( new String( inFile.data, start, endNoCfml - start) ); inFile.setPeekIndx(endNoCfml+9); inFile.reset(); bReadingTag = false; continue; } } else { // at this point, we don't recognize the tag as a supported tag if (tag.toString().toUpperCase().startsWith("<CF") && !(tagClass instanceof ContentTypeStaticInterface)) { inFile.addException(catchDataFactory.tagNotRecognizedException(tag.toString(), inFile.curLine, inFile.curColumn - tag.length())); } // It wasn't. So reset the reader to the marked position // just after the '<' and let the parsing continue from there // Note: this previously just dumped the contents to the buffer // and continued onwards but there was a bug within a cfquery tag '< // #createodbcdatetime( ' tagBuffer.write('<'); inFile.reset(); bReadingTag = false; continue; } } else { // Now read in the rest of the tag note these in case there's a parsing error int tagLine = inFile.curLine; int tagCol = inFile.curColumn; tagElement = readTagElement(inFile, tag); if (tagElement == null) { inFile.addException(catchDataFactory.tagParseException(tag.toString(), tagLine, tagCol)); break; } else { determineCFtag(inFile, tagElement, tagBuffer); } bReadingTag = false; } } } else { if ((character == CHAR_HASH) && (_endTagMarker != null) && embeddedSigns) { readHashExpression(inFile, tagBuffer); } else if ( character == TAG_END_MARKER && lastcharactor == CHAR_PERCENT && (_endTagMarker != null) && _endTagMarker.equals("%>") ){ break; } else { lastcharactor = character; tagBuffer.write(character); } } } // Update the contents tagClass.tagContents = tagBuffer.toCharArray(); // We have a little too many characters if ( tagClass instanceof cfOUTPUTRails ){ if ( character != TAG_END_MARKER && lastcharactor != CHAR_PERCENT ){ inFile.addException( catchDataFactory.noEndTagException(tagClass) ); return; } tagClass.tagContents = Arrays.copyOf( tagClass.tagContents, tagClass.tagContents.length - 1 ); } } // ----------------------------------------------------- private cfTag createTag(tagReader _inFile, String _tag) throws IOException, cfmBadFileException { // Is this tag one of the tags inwhich we support? String tag = getTagName(_tag); boolean bTagAvailable = cfEngine.thisInstance.TagChecker.isTagAvailable(tag); boolean bCustomTag = false; boolean bImportedCustomTag = false; if (!bTagAvailable) { bCustomTag = cfmlFileCache.isCustomTag(tag); if (!bCustomTag) bImportedCustomTag = isImportedTag(tag);// importedMappings.containsKey(tag.toUpperCase() ); } if (!bTagAvailable && !bCustomTag && !bImportedCustomTag) return null; boolean bTagSupported = cfEngine.thisInstance.TagChecker.isTagSupported(tag); if (!bCustomTag && !bTagSupported && !bImportedCustomTag) { _inFile.addException(catchDataFactory.tagNotSupportedException(_tag, _inFile.curLine, _inFile.curColumn - _tag.length())); return null; } cfTag tg; try { Class<?> C; if (tag != null && !bCustomTag && bTagSupported) // look for it from the XML definition file C = Class.forName(cfEngine.thisInstance.TagChecker.getClass(tag)); else if (bCustomTag) { // could be a custom tag if (tag.indexOf("CFX") == 0) C = Class.forName("com.naryx.tagfusion.cfx.cfCFX"); else C = Class.forName("com.naryx.tagfusion.cfm.tag.cfCustomTag"); } else if (bImportedCustomTag) { C = Class.forName("com.naryx.tagfusion.cfm.tag.cfCustomTag"); } else return null; tg = (cfTag) C.newInstance(); tg.posLine = _inFile.curLine; tg.posColumn = _inFile.curColumn - _tag.length(); if (tg.posColumn < 1) tg.posColumn = _inFile.curColumn; } catch (Exception E) { throw new cfmBadFileException(catchDataFactory.classNotFoundException(_tag, _inFile.curLine, _inFile.curColumn - _tag.length())); } // Setup the tag with the various parameters tg.setParentTag(this.tagClass); if (bImportedCustomTag) { ((cfCustomTag) tg).defaultParameters(_tag, getImportedMapping(tag)); } else if (_tag.endsWith("/>")) { tg.defaultParameters(_tag.substring(0, _tag.length() - 2) + ">"); } else tg.defaultParameters(_tag); // Make a check for the optional tag body processing if (tg instanceof cfOptionalBodyTag) { if (!_tag.endsWith("/>")) ((cfOptionalBodyTag) tg).lookAheadForEndTag(_inFile); else ((cfOptionalBodyTag) tg).setEndTag(); } else if (tg instanceof cfIMPORT) { if ( !tg.containsAttribute( "PATH" ) ){ String prefix = ((cfIMPORT) tg).getPrefix().toUpperCase(); String dir = ((cfIMPORT) tg).getDirectory(); // if prefix has already been defined, add the directory to the list if (importedMappings.containsKey(prefix)) { dir = importedMappings.get(prefix) + "," + dir; } importedMappings.put(prefix, dir); } } if (tg instanceof cfSCRIPT) { if ( !tg.containsAttribute("LANGUAGE") || tg.getConstant("LANGUAGE").equalsIgnoreCase("cfscript") ){ ((cfSCRIPT) tg).setStatement(readCFSCRIPT((cfSCRIPT) tg, _inFile)); }else{ cfSCRIPT newLangImp = cfSCRIPT.getLanguage(tg.getConstant("LANGUAGE")); if ( newLangImp != null ){ newLangImp.setParentFile( tg.getFile() ); newLangImp.setParentTag( tg.parentTag ); newLangImp.setProperties( tg.getProperties() ); tg = newLangImp; new cfParseTag(tg, importedMappings ).readTag(_inFile, tg.getEndMarker()); }else{ throw new cfmBadFileException( catchDataFactory.generalException("CFSCRIPT", "Invalid LANGUAGE='" + tg.getConstant("LANG") + "'" ) ); } } tg.posEndColumn = _inFile.curColumn -tg.getTagName().length() - 2; tg.posEndLine = _inFile.curLine; } else if (!_tag.endsWith("/>") && tg.getEndMarker() != null) { _inFile.pushStartTag(tg); new cfParseTag(tg, importedMappings ).readTag(_inFile, tg.getEndMarker()); tg.posEndColumn = _inFile.curColumn - tg.getTagName().length() - 2; tg.posEndLine = _inFile.curLine; } return tg; } private static CFScriptStatement readCFSCRIPT(cfSCRIPT _script, tagReader _reader) throws cfmBadFileException { // note reader positions before starting to read int start = _reader.currentIndx; int col = _reader.curColumn; int line = _reader.curLine; try { /* * The ANTLR parser will consume the entire input stream provided to it * which is not very efficient and also leaves our poundSignFilterStream * with an inaccurate 'added' count. * * So we do a crude search for the end tag with a string search to find * the script block. The only problem being the scenario where '</cfscript>' * appears in the block as part of a string. To handle this, we keep searching * for the end tag until we find a successfully parsing block, or we reach the * end of the file (upon which the original Exception is thrown */ int endScript = _reader.nextIndexOf("</CFSCRIPT>", start); if (endScript > 0) { endScript += 11; } poundSignFilterStream psf = null; ANTLRNoCaseReaderStream input = null; CFMLLexer lexer = null; ParserRuleReturnScope r = null; CommonTokenStream tokens = null; Exception firstException = null; while (endScript > 0) { try { String scriptBlock = new String(_reader.data, start, endScript - start); psf = new poundSignFilterStream(new StringReader(scriptBlock)); input = new ANTLRNoCaseReaderStream(psf); lexer = new CFMLLexer(input); tokens = new CommonTokenStream(lexer); CFMLParser parser = new CFMLParser(tokens); r = parser.scriptBlock(); } catch (Exception e) { if (firstException == null) { firstException = e; } endScript = _reader.nextIndexOf("</CFSCRIPT>", endScript); if (endScript > 0) { endScript += 11; continue; } } break; } if (r == null) { // we did not successfully find a parsable script block if (firstException != null) { throw firstException; } throw new cfmBadFileException(catchDataFactory.noEndTagException(_script)); } CommonTree tree = (CommonTree) r.getTree(); // need to check the child count. It will be 0 if the script tag only // contains comments // otherwise, the last child should be the </CFSCRIPT> tag if (tree.getChildCount() > 0) { CommonTree t2 = (CommonTree) tree.getChild(tree.getChildCount() - 1); if (t2.token != null && t2.token.getType() != CFMLParser.SCRIPTCLOSE) { throw new cfmBadFileException(catchDataFactory.noEndTagException(_script)); } } CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree); nodes.setTokenStream(tokens); CFMLTree p2 = new CFMLTree(nodes); CFScriptStatement statement = p2.scriptBlock(); List<String> importPaths = p2.getImportPaths(); if ( importPaths.size() > 0 ){ _script.getFile().addImportPaths( importPaths ); } // having parsed the tagReader input to the end tag </CFSCRIPT>, the // tagReader will be left in a position just beyond that tag. // So first get the positions that the parser's SimpleCharStream is at int newCol = input.getCharPositionInLine(); int newLine = input.getLine(); int newStart = start + lexer.getCharIndex(); // now work out the position in the tagReader that the cfscript // block ends. As well as including the SimpleCharStream position from // above we also need to adjust for the chars added/removed by the // poundSignFilterStream. _reader.currentIndx = newStart - psf.getAdded(); _reader.curColumn = newCol + 1; _reader.curLine = line + newLine - 1; // DEBUG: String scriptblock = new String( _reader.data, start, // _reader.currentIndx-start ); // find special cases of "#varName#"="value"; // note that only the char [] that represents the <cfscript> block // contents is passed in sourceReader sr = new sourceReader(new BufferedReader(new CharArrayReader(_reader.data, start, _reader.currentIndx - 11 - start))); statement.checkIndirectAssignments(sr.getLines()); int scriptBodyLen = _reader.currentIndx - start; char[] tagBody = new char[scriptBodyLen]; for (int i = 0; i < scriptBodyLen; i++) { tagBody[i] = _reader.data[start + i]; } _script.tagContents = tagBody; return statement; } catch (poundSignFilterStreamException e) { // reset the reader to start of the cfscript block _reader.curLine = line; _reader.curColumn = col; throw new cfmBadFileException(catchDataFactory.extendedScriptException("errorCode.badFormat", "expression.Parse", new String[] { e.getMessage() }, 0, 0)); } catch (RecognitionException e) { com.nary.Debug.printStackTrace( e ); _reader.curLine = line + e.line - 1; _reader.curColumn = e.charPositionInLine + 1; String msg = e.getMessage(); if (e instanceof NoViableAltException && e.token != null) { msg = "Encountered invalid token after \"" + e.token.getText() + "\""; } throw new cfmBadFileException(catchDataFactory.extendedScriptException("errorCode.badFormat", "expression.Parse", new String[] { msg }, 0, 0)); } catch (ParseException e) { _reader.curLine = line + e.getLine() - 1; _reader.curColumn = e.getCol() + 1; throw new cfmBadFileException(catchDataFactory.extendedScriptException("errorCode.badFormat", "expression.Parse", new String[] { e.getMessage() }, 0, 0)); } catch (cfmBadFileException e) { throw e; } catch (Exception e) { com.nary.Debug.printStackTrace( e ); throw new cfmBadFileException(catchDataFactory.extendedScriptException("errorCode.badFormat", "expression.Parse", new String[] { "Error parsing <CFSCRIPT> block: " + e.getMessage() }, line, col)); } } private cfTag createCFOutputRails(tagReader _inFile, CharArrayWriter _tagBuffer) { cfTag tagInst = new cfOUTPUTRails(); tagClass.tagList.add(tagInst); _tagBuffer.write(cfTag.TAG_MARKER); return tagInst; } private void determineCFtag(tagReader _inFile, String _tag, CharArrayWriter _tagBuffer) throws IOException, cfmBadFileException { cfTag tagInst = createTag(_inFile, _tag); if (tagInst != null) { // tag is a CFML tag // ignore CFASSERT tags if assertions disabled if (!(tagInst instanceof cfASSERT) || cfEngine.isAssertionsEnabled()) { tagClass.tagList.add(tagInst); _tagBuffer.write(cfTag.TAG_MARKER); } } else { // tag is not a CFML tag, copy it to the buffer _tagBuffer.write(_tag); } } // ----------------------------------------------------- private boolean isImportedTag(String _tag) { String prefix = getPrefix(_tag); return (prefix == null ? false : importedMappings.containsKey(prefix.toUpperCase())); } private static String getPrefix(String _tag) { int colonIndex = _tag.indexOf(':'); int underscoreIndex = _tag.indexOf('_'); if (colonIndex != -1) { return _tag.substring(0, colonIndex); } else if (underscoreIndex != -1) { return _tag.substring(0, underscoreIndex); } else { return null; } } private String getImportedMapping(String _tag) { String prefix = getPrefix(_tag); return importedMappings.get(prefix.toUpperCase()); } // ----------------------------------------------------- private static String getTagName(String tag) { try { int tagStart = 1; // start at position 1 to bypass opening < for (int i = tagStart; i < tag.length(); i++) { if (!Character.isWhitespace(tag.charAt(i))) { tagStart = i; break; } } int tagEnd = -1; for (int x = tagStart; x < tag.length(); x++) { if (isTagNameTerminatingChar(tag.charAt(x))) { tagEnd = x; break; } } if (tagEnd == -1) { if (tag.endsWith("/>")) { return tag.substring(tagStart, tag.length() - 2).toUpperCase(); } else { return tag.substring(tagStart, tag.length() - 1).toUpperCase(); } } else { return tag.substring(tagStart, tagEnd).toUpperCase(); } } catch (Exception E) { return null; } } protected static boolean isWhiteSpace(int character) { return ((character == CHAR_SPACE) || (character == CHAR_CARRIAGERETURN) || (character == CHAR_LINEFEED) || (character == CHAR_TAB)); } protected static boolean isTagNameTerminatingChar(int character) { return ((character == CHAR_SPACE) || (character == CHAR_CARRIAGERETURN) || (character == CHAR_LINEFEED) || (character == CHAR_TAB) || (character == CHAR_HASH) || (character == CHAR_OPEN_PAREN)); } private boolean isTagSupported(String tag) { if (cfEngine.thisInstance.TagChecker.isTagAvailable(tag) || cfmlFileCache.isCustomTag(tag) || this.isImportedTag(tag)) return true; else return false; } private static int readCommentTag(tagReader inFile) { StringBuilder tag = new StringBuilder(32); int counter = 1; int character; int matchSI = 0; int matchEI = 0; int startLine = inFile.curLine; while ((character = inFile.read()) != -1) { tag.append((char) character); if (character == matchStart[matchSI]) { if (matchSI == 4) { counter++; tag = new StringBuilder(32); matchSI = 0; } else { matchSI++; } } else if (character == matchEnd[matchEI]) { if (matchEI == 3) { --counter; if (counter == 0) break; matchEI = 0; tag = new StringBuilder(32); } else { matchEI++; } } else if (matchSI != 0) { matchSI = 0; } else if (!(matchEI == 3 && character == '-')) { matchEI = 0; } } if (startLine != inFile.curLine) { return inFile.curLine; } else { return 0; } } /** * This method reads the remainder part of the tagelement and returns * the completed tag. ie "<CFSET asdalk=asdasd>" would be returned * * Method enabled for the special escaping of the <cfif> / <cfelseif> tags * to support the [] escape syntax. This enables us to use <, > operators * within the tag without corrupting the tag parser * * @param inFile * @param tag * @return */ private static String readTagElement(tagReader inFile, StringBuilder tag) { if (tag.charAt(tag.length() - 1) == TAG_END_MARKER) return tag.toString(); // For special case, <cfif ()> / <cfelseif ()> to cope with the > >= operators boolean braceEscapable = false, braceEscapeStarted = false; int braceEscapeCount = 0; String tmpTag = tag.toString().toLowerCase(); if ( tmpTag.indexOf("<cfif") == 0 || tmpTag.indexOf("<cfelseif") == 0 ){ braceEscapable = true; } // Run through and look for the ">" character int character; StringBuilder blockChars = new StringBuilder(8); while ((character = inFile.read()) != -1) { tag.append( (char)character ); //Check for the escapable area for <cfif> <cfelseif> tags that lets us do <cfif [2>1]> if ( braceEscapable ){ if ( !braceEscapeStarted ){ if ( !isWhiteSpace(character) ){ if ( character == CHAR_OPEN_PAREN ){ braceEscapeStarted = true; braceEscapeCount = 1; }else{ braceEscapable = false; // this is a normal expression, not being escaped, so bypass all this logic } } }else if ( braceEscapeStarted && character == CHAR_OPEN_PAREN && blockChars.length() == 0 ){ braceEscapeCount++; }else if ( braceEscapeStarted && character == CHAR_CLOSE_PAREN && blockChars.length() == 0 ){ braceEscapeCount--; } } //Check for the end marker if none has been specified if (character == CHAR_DOUBLEQUOTE || character == CHAR_SINGLEQUOTE || character == CHAR_HASH) { if (blockChars.length() > 0) { char lastChar = blockChars.charAt(blockChars.length() - 1); if (blockChars.length() > 0 && character == lastChar) { blockChars.deleteCharAt(blockChars.length() - 1); } else if (!((character == CHAR_DOUBLEQUOTE && lastChar == CHAR_SINGLEQUOTE) || (character == CHAR_SINGLEQUOTE && lastChar == CHAR_DOUBLEQUOTE))) { blockChars.append((char) character); } } else { blockChars.append((char) character); } } else if (character == TAG_END_MARKER && blockChars.length() == 0 && braceEscapeCount == 0) break; } return tag.toString(); } // -------------------------------------------------------- private static boolean foundTag(String needTag, String tag) { return getTagName(needTag).equalsIgnoreCase(getTagName(tag).trim()); } // -------------------------------------------------------- private boolean checkEndTag(String tag) { tag = getTagName(tag).trim(); // This method takes the tag and see's if its a tag that should have an opening tag if (tag.length() == 0 || tag.charAt(0) != CHAR_FORWARDSLASH) return false; // The tag is in the format </XXXX> tag = tag.substring(1); return (cfEngine.thisInstance.TagChecker.isTagAvailable(tag) && cfEngine.thisInstance.TagChecker.isTagSupported(tag)) || cfmlFileCache.isCustomTag(tag) || isImportedTag(tag); } // -------------------------------------------------------- private boolean doesTagHaveEmbeddedPoundSigns() { return (tagClass == null ? false : tagClass.doesTagHaveEmbeddedPoundSigns()); } // -------------------------------------------------------- private static void readHashExpression(tagReader inFile, CharArrayWriter out) throws cfmBadFileException { /* * This method reads #...# expressions. It has to be noted that by the time of the call * the first # has been read from the input stream. We'll utilise the technology of the * cfOutputFilter to do all the escaping of the #'s. We will pass in null * to the output side of the cfOutputFilter, since we only want it to collect the * expression for us. */ cfOutputFilter outFilter = new cfOutputFilter(); try { outFilter.write(CHAR_HASH, out); int charIn; while ((charIn = inFile.read()) != -1) { if (outFilter.write(charIn, null)) break; } } catch (cfmBadFileException bfe) { // catch and rethrow because cfmBadFileException is a subclass of // cfmRunTimeException throw bfe; } catch (cfmRunTimeException ignore) { // will never happen because the code in outFilter.write() that throws // cfmRunTimeException is never executed because ( session == null ) } // Need to add the expression to the output out.write(CHAR_HASH); char chs[] = outFilter.getExpression().toCharArray(); out.write(chs, 0, chs.length); out.write(CHAR_HASH); } }