/*
* Copyright (C) 2000 - 2008 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.tag;
import java.util.Map;
/*
* This class is used to decode the tag attributes into a hashtable.
* The data for parameters in the tag can be delimited by spaces, tabs, quotes or single quotes.
*/
public final class tagParameters extends Object {
Map params;
char[] expArray;
int ptrIndex;
private static char SPACE = ' ';
private static char TAB = '\t';
private static char EQUALS = '=';
private static char QUOTE = '"';
private static char SINGLEQUOTE = '\'';
private static char NEWLINE = '\n';
private static char CARRIAGERETURN = '\r';
private static char HASH = '#';
public tagParameters( String _tag, boolean onlyOne, Map _params ) throws Exception {
params = _params;
int min = 9999;
int c1 = _tag.indexOf(" ");
if ( c1 != -1 && c1 < min )
min = c1;
c1 = _tag.indexOf(TAB);
if ( c1 != -1 && c1 < min )
min = c1;
c1 = _tag.indexOf( NEWLINE );
if ( c1 != -1 && c1 < min )
min = c1;
c1 = _tag.indexOf( CARRIAGERETURN );
if ( c1 != -1 && c1 < min )
min = c1;
if ( min == 9999 ) return;
String tag = _tag.substring( min, _tag.length()-1 );
if ( onlyOne ){
c1 = tag.indexOf("=");
if ( c1 == -1 )
throw new Exception();
String key = tag.substring( 0, c1 ).toUpperCase().trim();
String value = tag.substring( c1+1 ).trim();
params.put( key, value );
} else {
expArray = new char[ tag.length() ];
ptrIndex = 0;
tag.getChars( 0, tag.length(), expArray, 0 );
parseArray();
}
}// tagParameters()
private void parseArray() throws Exception {
String key = null,data = null;
while ( ptrIndex < expArray.length ){
if ( key != null && Character.isJavaIdentifierStart( expArray[ ptrIndex ] ) ){
params.put( key.toUpperCase(), "true" );
key = readKey();
} else if ( key == null && Character.isJavaIdentifierStart( expArray[ ptrIndex ] ) ){
key = readKey();
} else if ( key != null && expArray[ ptrIndex ] == EQUALS ) {
ptrIndex++;
data = readData();
params.put( key.toUpperCase(), data );
key = data = null;
} else
ptrIndex++;
}
//--[ If there was a final attribute at the end
if ( key != null )
params.put( key.toUpperCase(), "true" );
}// parseArray()
private String readData() throws Exception {
//--[ Skip white space
while ( (ptrIndex < expArray.length) && (expArray[ ptrIndex ] == SPACE
|| expArray[ ptrIndex ] == TAB || expArray[ ptrIndex ] == NEWLINE
|| expArray[ ptrIndex ] == CARRIAGERETURN))
ptrIndex++;
StringBuilder data = new StringBuilder();
char delimitor = ' ';
if ( expArray[ ptrIndex ] == QUOTE || expArray[ ptrIndex ] == SINGLEQUOTE || expArray[ ptrIndex ] == HASH ){
data.append( expArray[ ptrIndex ] );
delimitor = expArray[ ptrIndex ];
ptrIndex++;
StringBuilder signChars = new StringBuilder();
signChars.append( delimitor );
while ( ptrIndex < expArray.length ){
// check for escape sequence first
if ( expArray[ ptrIndex ] == delimitor
&& ((ptrIndex + 1) < expArray.length) && (expArray[ ptrIndex + 1 ] == delimitor)){
data.append( expArray[ ptrIndex ] );
ptrIndex++; // if escape sequence then advance past the first char of the escape seq. The chars that apply are " and '
}else if ( expArray[ ptrIndex ] == QUOTE || expArray[ ptrIndex ] == SINGLEQUOTE || expArray[ ptrIndex ] == HASH ){
char lastSignChar = signChars.charAt( signChars.length()-1 );
if ( expArray[ptrIndex] == lastSignChar ){
if ( signChars.length() == 1 ){
// we have reached the last char
data.append( expArray[ ptrIndex ] );
break;
}else{
signChars.deleteCharAt( signChars.length()-1 ); // remove last significant char
}
// NOT (if this is a single quote within a double quote delimited string or vice versa)
}else if ( !( ( expArray[ ptrIndex ] == QUOTE && lastSignChar == SINGLEQUOTE )
|| ( expArray[ ptrIndex ] == SINGLEQUOTE && lastSignChar == QUOTE ) ) ){
signChars.append( expArray[ptrIndex] );
}
}
data.append( expArray[ ptrIndex ] );
ptrIndex++;
}
// if not delimited by quotes or #, then we can simplify the logic for parsing this
}else{
// write char to data and move pointer on
data.append( expArray[ ptrIndex++ ] );
while ( ptrIndex < expArray.length ){
if ( expArray[ ptrIndex ] == SPACE || expArray[ ptrIndex ] == TAB
|| expArray[ ptrIndex ] == CARRIAGERETURN || expArray[ ptrIndex ] == NEWLINE ){
break;
}else if ( expArray[ ptrIndex ] == HASH || expArray[ ptrIndex ] == QUOTE || expArray[ ptrIndex ] == SINGLEQUOTE ){
throw new Exception( "Unexpected character found: " + expArray[ptrIndex] );
}else{
data.append( expArray[ ptrIndex++ ] );
}
}
}
return data.toString().trim();
}
private String readKey() throws Exception {
StringBuilder identifier = new StringBuilder();
identifier.append( expArray[ ptrIndex ] );
int sqBracket = 0;
ptrIndex++;
while ( ptrIndex < expArray.length ){
if ( expArray[ ptrIndex ] == '[' )
sqBracket++;
else if ( expArray[ ptrIndex ] == ']' )
--sqBracket;
else if ( !(Character.isJavaIdentifierPart(expArray[ ptrIndex ]) || expArray[ ptrIndex ] == ':' ) && sqBracket == 0 && expArray[ ptrIndex ] != '.' )
break;
identifier.append( expArray[ ptrIndex ] );
ptrIndex++;
}
return identifier.toString();
}
}