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.type.scope; 020 021import java.io.UnsupportedEncodingException; 022 023import lucee.commons.lang.StringList; 024import lucee.commons.lang.StringUtil; 025import lucee.commons.net.URLDecoder; 026import lucee.commons.net.URLItem; 027import lucee.runtime.PageContext; 028import lucee.runtime.dump.DumpData; 029import lucee.runtime.dump.DumpProperties; 030import lucee.runtime.exp.ExpressionException; 031import lucee.runtime.op.Caster; 032import lucee.runtime.security.ScriptProtect; 033import lucee.runtime.type.Array; 034import lucee.runtime.type.ArrayImpl; 035import lucee.runtime.type.CastableStruct; 036import lucee.runtime.type.Collection; 037import lucee.runtime.type.KeyImpl; 038import lucee.runtime.type.Sizeable; 039import lucee.runtime.type.Struct; 040import lucee.runtime.type.StructImpl; 041import lucee.runtime.type.util.ListUtil; 042import lucee.runtime.type.util.StructUtil; 043 044 045 046/** 047 * Simple standart implementation of a Scope, for standart use. 048 */ 049public abstract class ScopeSupport extends StructImpl implements Scope,Sizeable { 050 051 private static final long serialVersionUID = -4185219623238374574L; 052 053 private String name; 054 private String dspName; 055 private static int _id=0; 056 private int id=0; 057 private static final byte[] EMPTY="".getBytes(); 058 059 060 /** 061 * Field <code>isInit</code> 062 */ 063 protected boolean isInit; 064 private int type; 065 066 /** 067 * constructor for the Simple class 068 * @param name name of the scope 069 * @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use) 070 */ 071 public ScopeSupport(boolean sync,String name, int type) { 072 super(sync?StructImpl.TYPE_SYNC:StructImpl.TYPE_UNDEFINED); 073 this.name=name; 074 this.type=type; 075 076 id=++_id; 077 } 078 /** 079 * constructor for ScopeSupport 080 * @param name name of the scope 081 * @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use) 082 * @param doubleLinked mean that the struct has predictable iteration order this make the input order fix 083 */ 084 public ScopeSupport(String name, int type, int mapType) { 085 super(mapType); 086 this.name=name; 087 this.type=type; 088 089 id=++_id; 090 } 091 092 @Override 093 094 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 095 return toDumpData(pageContext, maxlevel, dp, this, dspName); 096 } 097 098 public static DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, Struct sct,String dspName) { 099 if(StringUtil.isEmpty(dspName))dspName="Scope"; 100 101 return StructUtil.toDumpTable(sct, dspName, pageContext, maxlevel, dp); 102 103 } 104 105 protected ExpressionException invalidKey(String key) { 106 return new ExpressionException("variable ["+key+"] doesn't exist in "+StringUtil.ucFirst(name)+" Scope (keys:"+ListUtil.arrayToList(keys(), ",")+")"); 107 } 108 109 /** 110 * write parameter defined in a query string (name1=value1&name2=value2) to the scope 111 * @param qs Query String 112 * @return parsed name value pair 113 */ 114 protected static URLItem[] setFromQueryString(String str) { 115 return setFrom___(str, '&'); 116 } 117 118 protected static URLItem[] setFromTextPlain(String str) { 119 return setFrom___(str, '\n'); 120 } 121 protected static URLItem[] setFrom___(String tp,char delimiter) { 122 if(tp==null) return new URLItem[0]; 123 Array arr=ListUtil.listToArrayRemoveEmpty(tp,delimiter); 124 URLItem[] pairs=new URLItem[arr.size()]; 125 126 //Array item; 127 int index; 128 String name; 129 130 for(int i=1;i<=pairs.length;i++) { 131 name=Caster.toString(arr.get(i,""),""); 132 //if(name.length()==0) continue; 133 134 index=name.indexOf('='); 135 if(index!=-1) pairs[i-1]=new URLItem(name.substring(0,index),name.substring(index+1),true); 136 else pairs[i-1]=new URLItem(name,"",true); 137 138 } 139 return pairs; 140 } 141 142 protected static byte[] getBytes(String str) { 143 return str.getBytes(); 144 } 145 protected static byte[] getBytes(String str,String encoding) { 146 try { 147 return str.getBytes(encoding); 148 } catch (UnsupportedEncodingException e) { 149 return EMPTY; 150 } 151 } 152 153 protected void fillDecodedEL(URLItem[] raw, String encoding, boolean scriptProteced, boolean sameAsArray) { 154 try { 155 fillDecoded(raw, encoding,scriptProteced,sameAsArray); 156 } catch (UnsupportedEncodingException e) { 157 try { 158 fillDecoded(raw, "iso-8859-1",scriptProteced,sameAsArray); 159 } catch (UnsupportedEncodingException e1) {} 160 } 161 } 162 163 164 /** 165 * fill th data from given strut and decode it 166 * @param raw 167 * @param encoding 168 * @throws UnsupportedEncodingException 169 */ 170 protected void fillDecoded(URLItem[] raw, String encoding, boolean scriptProteced, boolean sameAsArray) throws UnsupportedEncodingException { 171 clear(); 172 String name,value; 173 //Object curr; 174 for(int i=0;i<raw.length;i++) { 175 name=raw[i].getName(); 176 value=raw[i].getValue(); 177 if(raw[i].isUrlEncoded()) { 178 name=URLDecoder.decode(name,encoding,true); 179 value=URLDecoder.decode(value,encoding,true); 180 } 181 // MUST valueStruct 182 if(name.indexOf('.')!=-1) { 183 StringList list=ListUtil.listToStringListRemoveEmpty(name,'.'); 184 Struct parent=this; 185 while(list.hasNextNext()) { 186 parent=_fill(parent,list.next(),new CastableStruct(),false,scriptProteced,sameAsArray); 187 } 188 _fill(parent,list.next(),value,true,scriptProteced,sameAsArray); 189 } 190 //else 191 _fill(this,name,value,true,scriptProteced,sameAsArray); 192 } 193 } 194 195 private Struct _fill(Struct parent, String name, Object value, boolean isLast, boolean scriptProteced, boolean sameAsArray) { 196 Object curr; 197 boolean isArrayDef=sameAsArray; 198 Collection.Key key=KeyImpl.init(name); 199 200 // script protect 201 if(scriptProteced && value instanceof String) { 202 value=ScriptProtect.translate((String)value); 203 } 204 205 if(name.length() >2 && name.endsWith("[]")) { 206 isArrayDef=true; 207 name=name.substring(0,name.length()-2); 208 key=KeyImpl.getInstance(name); 209 curr=parent.get(key,null); 210 } 211 else { 212 curr=parent.get(key,null); 213 } 214 215 if(curr==null) { 216 if(isArrayDef) { 217 Array arr = new ArrayImpl(); 218 arr.appendEL(value); 219 parent.setEL(key,arr); 220 } 221 else parent.setEL(key,value); 222 } 223 else if(curr instanceof Array){ 224 ((Array) curr).appendEL(value); 225 } 226 else if(curr instanceof CastableStruct){ 227 if(isLast) ((CastableStruct)curr).setValue(value); 228 else return (Struct) curr; 229 230 } 231 else if(curr instanceof Struct){ 232 if(isLast) parent.setEL(key,value); 233 else return (Struct) curr; 234 } 235 else if(curr instanceof String){ 236 if(isArrayDef) { 237 Array arr = new ArrayImpl(); 238 arr.appendEL(curr); 239 arr.appendEL(value); 240 parent.setEL(key,arr); 241 } 242 else if(value instanceof Struct) { 243 parent.setEL(key,value); 244 } 245 else { 246 if(!StringUtil.isEmpty(value)) { 247 String existing=Caster.toString(curr,""); 248 if(StringUtil.isEmpty(existing)) 249 parent.setEL(key,value); 250 else 251 parent.setEL(key,Caster.toString(curr,"")+','+value); 252 } 253 } 254 } 255 if(!isLast) { 256 return (Struct)value; 257 } 258 return null; 259 } 260 261 /* 262 private String decode(Object value,String encoding) throws UnsupportedEncodingException { 263 return URLDecoder.decode(new String(Caster.toString(value,"").getBytes("ISO-8859-1"),encoding),encoding); 264 }*/ 265 266 @Override 267 public boolean isInitalized() { 268 return isInit; 269 } 270 271 @Override 272 public void initialize(PageContext pc) { 273 isInit=true; 274 } 275 276 @Override 277 public void release() { 278 clear(); 279 isInit=false; 280 } 281 282 @Override 283 public void release(PageContext pc) { 284 clear(); 285 isInit=false; 286 } 287 288 289 /** 290 * @return Returns the id. 291 */ 292 public int _getId() { 293 return id; 294 } 295 296 /** 297 * display name for dump 298 * @param dspName 299 */ 300 protected void setDisplayName(String dspName) { 301 this.dspName=dspName; 302 } 303 304 @Override 305 public int getType() { 306 return type; 307 } 308 309 @Override 310 public String getTypeAsString() { 311 return name; 312 } 313 public long sizeOf() { 314 return StructUtil.sizeOf(this); 315 } 316 317}