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.transformer.bytecode.literal;
020
021import lucee.commons.io.CharsetUtil;
022import lucee.commons.lang.ExceptionUtil;
023import lucee.commons.lang.StringUtil;
024import lucee.runtime.config.ConfigImpl;
025import lucee.runtime.op.Caster;
026import lucee.transformer.bytecode.BytecodeContext;
027import lucee.transformer.bytecode.BytecodeException;
028import lucee.transformer.bytecode.Literal;
029import lucee.transformer.bytecode.Page;
030import lucee.transformer.bytecode.Position;
031import lucee.transformer.bytecode.expression.ExprString;
032import lucee.transformer.bytecode.expression.ExpressionBase;
033import lucee.transformer.bytecode.op.OpString;
034import lucee.transformer.bytecode.util.Types;
035
036import org.objectweb.asm.Opcodes;
037import org.objectweb.asm.Type;
038import org.objectweb.asm.commons.GeneratorAdapter;
039
040/**
041 * A Literal String
042 */
043public class LitString extends ExpressionBase implements Literal,ExprString {
044    
045        public static final int MAX_SIZE = 65535;
046        public static final int TYPE_ORIGINAL = 0;
047        public static final int TYPE_UPPER = 1;
048        public static final int TYPE_LOWER = 2;
049        public static final LitString EMPTY = new LitString("",null,null);
050         
051        private String str;
052        private boolean fromBracket;
053
054        public static ExprString toExprString(String str, Position start,Position end) {
055                return new LitString(str,start,end);
056        }
057
058        public static ExprString toExprString(String str) {
059                return new LitString(str,null,null);
060        }
061
062        public static LitString toLitString(String str) {
063                return new LitString(str,null,null);
064        }
065
066    /**
067     * constructor of the class
068     * @param str
069     * @param line 
070     */
071        public LitString(String str, Position start,Position end) {
072        super(start,end);
073        this.str=str;
074    }
075    
076    /**
077     * @see lucee.transformer.bytecode.Literal#getString()
078     */
079    public String getString() {
080        return str;
081    }
082
083    /**
084     * @throws BytecodeException 
085     * @see lucee.transformer.bytecode.expression.Expression#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
086     */
087    private static  Type _writeOut(BytecodeContext bc, int mode,String str) throws BytecodeException {
088        // write to a file instead to the bytecode
089        // str(0,10);
090        //print.ds(str);
091        int externalizeStringGTE=((ConfigImpl)bc.getPageSource().getMapping().getConfig()).getExternalizeStringGTE();
092        
093        if(externalizeStringGTE>-1 && str.length()>externalizeStringGTE && StringUtil.indexOfIgnoreCase(bc.getMethod().getName(),"call")!=-1) {
094                try{
095                        GeneratorAdapter ga = bc.getAdapter();
096                        Page page = bc.getPage();
097                        Range range= page.registerString(bc,str);
098                        ga.visitVarInsn(Opcodes.ALOAD, 0);
099                        ga.visitVarInsn(Opcodes.ALOAD, 1);
100                        ga.push(range.from);
101                        ga.push(range.to);
102                        ga.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), "str", "(Llucee/runtime/PageContext;II)Ljava/lang/String;");
103                        return Types.STRING;
104                }
105                catch(Throwable t){
106                        ExceptionUtil.rethrowIfNecessary(t);
107                }
108        }
109        
110        if(toBig(str)) {
111                _toExpr(str).writeOut(bc, mode);
112        }
113        else {
114                bc.getAdapter().push(str);
115        }
116        return Types.STRING;
117    }
118
119    private static ExprString _toExpr(String str) {
120        int size=str.length()/2;
121        String l = str.substring(0,size);
122        String r = str.substring(size);
123        ExprString left =toBig(l)? _toExpr(l):toExprString(l);
124        ExprString right =toBig(r)? _toExpr(r):toExprString(r);
125        return OpString.toExprString(left, right, false);
126        }
127    
128    
129    private static boolean toBig(String str) {
130                if(str.length()<(MAX_SIZE/2)) return false; // a char is max 2 bytes
131        return str.getBytes(CharsetUtil.UTF8).length>MAX_SIZE;
132        }
133
134        public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
135        return _writeOut(bc, mode, str);
136    }
137    
138    public Type writeOut(BytecodeContext bc, int mode, int caseType) throws BytecodeException {
139        if(TYPE_UPPER==caseType)        return _writeOut(bc, mode, str.toUpperCase());
140        if(TYPE_LOWER==caseType)        return _writeOut(bc, mode, str.toLowerCase());
141        return _writeOut(bc, mode, str);
142    }
143
144
145
146    /**
147     * @see lucee.transformer.bytecode.Literal#getDouble(java.lang.Double)
148     */
149    public Double getDouble(Double defaultValue) {
150        return Caster.toDouble(getString(),defaultValue);
151    }
152
153    /**
154     * @see lucee.transformer.bytecode.Literal#getBoolean(java.lang.Boolean)
155     */
156    public Boolean getBoolean(Boolean defaultValue) {
157        return Caster.toBoolean(getString(),defaultValue);
158    }
159    
160
161    /**
162         *
163         * @see java.lang.Object#equals(java.lang.Object)
164         */
165        public boolean equals(Object obj) {
166                if(this==obj) return true;
167                if(!(obj instanceof LitString)) return false;
168                return str.equals(((LitString)obj).str);
169        }
170
171        /**
172         *
173         * @see java.lang.Object#toString()
174         */
175        public String toString() {
176                return str;
177        }
178
179        public void upperCase() {
180                str=str.toUpperCase(); 
181        }
182        public void lowerCase() {
183                str=str.toLowerCase();
184        }
185
186        public LitString duplicate() {
187                return new LitString(str,getStart(),getEnd());
188        }
189
190        public void fromBracket(boolean fromBracket) {
191                this.fromBracket=fromBracket;
192        }
193        public boolean fromBracket() {
194                return fromBracket;
195        }
196
197
198        public static class Range {
199
200                public final int from;
201                public final int to;
202
203                public Range(int from, int to) {
204                        this.from=from;
205                        this.to=to;
206                }
207                public String toString(){
208                        return "from:"+from+";to:"+to+";";
209                }
210                
211        }
212
213    /* *
214     * @see lucee.transformer.bytecode.expression.Expression#getType()
215     * /
216    public int getType() {
217        return Types._STRING;
218    }*/
219}