001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.functions.decision;
020
021import lucee.runtime.PageContext;
022import lucee.runtime.exp.ExpressionException;
023import lucee.runtime.exp.FunctionException;
024import lucee.runtime.exp.PageException;
025import lucee.runtime.ext.function.Function;
026import lucee.runtime.op.Caster;
027import lucee.runtime.op.Decision;
028
029import org.apache.oro.text.regex.MalformedPatternException;
030import org.apache.oro.text.regex.Pattern;
031import org.apache.oro.text.regex.PatternMatcherInput;
032import org.apache.oro.text.regex.Perl5Compiler;
033import org.apache.oro.text.regex.Perl5Matcher;
034
035/**
036 * 
037 */
038public final class IsValid implements Function {
039
040        private static final long serialVersionUID = -1383105304624662986L;
041
042        /**
043         * check for many diff types
044         * @param pc
045         * @param type
046         * @param value
047         * @return
048         * @throws ExpressionException
049         */
050        public static boolean call(PageContext pc, String type, Object value) throws ExpressionException {
051                type=type.trim();
052
053                if("range".equalsIgnoreCase(type))
054                        throw new FunctionException(pc,"isValid",1,"type","for [range] you have to define a min and max value");
055
056                if("regex".equalsIgnoreCase(type) || "regular_expression".equalsIgnoreCase(type))
057                        throw new FunctionException(pc,"isValid",1,"type","for [regex] you have to define a pattern");
058
059                return Decision.isValid(type, value);
060        }
061        
062        /**
063         * regex check
064         * @param pc
065         * @param type
066         * @param value
067         * @param objPattern
068         * @return
069         * @throws PageException 
070         */
071        public static boolean call(PageContext pc, String type, Object value, Object objPattern) throws PageException {
072                type=type.trim();
073
074                if(!"regex".equalsIgnoreCase(type) && !"regular_expression".equalsIgnoreCase(type))
075                        throw new FunctionException(pc,"isValid",1,"type","wrong attribute count for type ["+type+"]");
076                
077                return regex(Caster.toString(value,null),Caster.toString(objPattern));
078        }
079        
080        
081        
082        
083        public static boolean regex(String value,String strPattern) {
084                if(value==null)
085                        return false;
086                
087                try {
088                        Pattern pattern = new Perl5Compiler().compile(strPattern, Perl5Compiler.MULTILINE_MASK);
089                PatternMatcherInput input = new PatternMatcherInput(value);
090                return new Perl5Matcher().matches(input, pattern);
091                } catch (MalformedPatternException e) {
092                        return false;
093                }
094        }
095
096        public static boolean call(PageContext pc, String type, Object value, Object objMin, Object objMax) throws PageException {
097                
098                // for named argument calls
099                if(objMax==null) {
100                        if(objMin==null) return call(pc, type, value);
101                        return call(pc, type, value, objMin);
102                }
103                
104                type=type.trim().toLowerCase();
105                
106                // numeric
107                if("range".equals(type) || "integer".equals(type) || "float".equals(type) || "numeric".equals(type)  || "number".equals(type) ) {
108                
109                        double number=Caster.toDoubleValue(value,true,Double.NaN);
110                        if(!Decision.isValid(number)) return false;
111                        
112                        double min=toRangeNumber(pc,objMin,3,"min");
113                        double max=toRangeNumber(pc,objMax,4,"max");
114                        
115                        
116                        return number>=min && number<=max;
117                }
118                else if("string".equals(type)){
119                        String str=Caster.toString(value,null);
120                        if(str==null) return false;
121                        
122                        double min=toRangeNumber(pc,objMin,3,"min");
123                        double max=toRangeNumber(pc,objMax,4,"max");
124                        
125                        return str.length()>=min && str.length()<=max;
126                }
127                
128                else
129                        throw new FunctionException(pc,"isValid",1,"type","wrong attribute count for type ["+type+"]");
130                        
131        }
132
133        private static double toRangeNumber(PageContext pc,Object objMin, int index,String name) throws FunctionException {
134                double d=Caster.toDoubleValue(objMin,false,Double.NaN);
135                if(!Decision.isValid(d))
136                        throw new FunctionException(pc,"isValid",index,name,"value must be numeric");
137                return d;
138        }
139}