156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/* 256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc. 356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License. 656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at 756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software 1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and 1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License. 1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.template; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.AutoEscapeContext; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.AutoEscapeOptions; 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DataContext; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.UniqueStack; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverAutoEscapingException; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverIOException; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException; 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.FunctionExecutor; 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader; 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value; 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException; 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.ArrayList; 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.HashMap; 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.List; 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Map; 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.logging.Logger; 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Default implementation of RenderingContext. 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class DefaultRenderingContext implements RenderingContext, FunctionExecutor { 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public static final Logger logger = Logger.getLogger(DefaultRenderingContext.class.getName()); 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final DataContext dataContext; 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final ResourceLoader resourceLoader; 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final Appendable out; 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final FunctionExecutor globalFunctionExecutor; 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final AutoEscapeOptions autoEscapeOptions; 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final UniqueStack<String> includeStack; 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private List<String> escaperStack = new ArrayList<String>(8); // seems like a reasonable initial 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // capacity. 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String currentEscaper; // optimization to reduce List lookup. 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private List<Template> executionStack = new ArrayList<Template>(8); 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private Map<String, Macro> macros = new HashMap<String, Macro>(); 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private List<EscapeMode> autoEscapeStack = new ArrayList<EscapeMode>(); 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private EscapeMode autoEscapeMode; 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private AutoEscapeContext autoEscapeContext; 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int line; 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int column; 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private AutoEscapeContext.AutoEscapeState startingAutoEscapeState; 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public DefaultRenderingContext(DataContext dataContext, ResourceLoader resourceLoader, 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Appendable out, FunctionExecutor globalFunctionExecutor, AutoEscapeOptions autoEscapeOptions) { 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.dataContext = dataContext; 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.resourceLoader = resourceLoader; 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.out = out; 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.globalFunctionExecutor = globalFunctionExecutor; 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.autoEscapeOptions = autoEscapeOptions; 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.autoEscapeMode = EscapeMode.ESCAPE_NONE; 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.autoEscapeContext = null; 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.includeStack = new UniqueStack<String>(); 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Lookup a function by name, execute it and return the results. 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Value executeFunction(String name, Value... args) { 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return globalFunctionExecutor.executeFunction(name, args); 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void escape(String name, String input, Appendable output) throws IOException { 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson globalFunctionExecutor.escape(name, input, output); 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean isEscapingFunction(String name) { 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return globalFunctionExecutor.isEscapingFunction(name); 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void pushEscapingFunction(String name) { 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson escaperStack.add(currentEscaper); 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (name == null || name.equals("")) { 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentEscaper = null; 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentEscaper = name; 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void popEscapingFunction() { 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int len = escaperStack.size(); 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (len == 0) { 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("No more escaping functions to pop."); 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentEscaper = escaperStack.remove(len - 1); 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void writeEscaped(String text) { 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // If runtime auto escaping is enabled, only apply it if 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // we are not going to do any other default escaping on the variable. 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson boolean applyAutoEscape = isRuntimeAutoEscaping() && (currentEscaper == null); 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (applyAutoEscape) { 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext.setCurrentPosition(line, column); 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson pushEscapingFunction(autoEscapeContext.getEscapingFunctionForCurrentState()); 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (shouldLogEscapedVariables()) { 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder tmp = new StringBuilder(); 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson globalFunctionExecutor.escape(currentEscaper, text, tmp); 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!tmp.toString().equals(text)) { 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson logger.warning(new StringBuilder(getLoggingPrefix()).append(" Auto-escape changed [") 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .append(text).append("] to [").append(tmp.toString()).append("]").toString()); 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson out.append(tmp); 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson globalFunctionExecutor.escape(currentEscaper, text, out); 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverIOException(e); 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } finally { 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (applyAutoEscape) { 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext.insertText(); 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson popEscapingFunction(); 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String getLoggingPrefix() { 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return "[" + getCurrentResourceName() + ":" + line + ":" + column + "]"; 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private boolean shouldLogEscapedVariables() { 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return (autoEscapeOptions != null && autoEscapeOptions.getLogEscapedVariables()); 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void writeUnescaped(CharSequence text) { 15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isRuntimeAutoEscaping() && (currentEscaper == null)) { 15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext.setCurrentPosition(line, column); 15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext.parseData(text.toString()); 15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson out.append(text); 16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverIOException(e); 16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void pushExecutionContext(Template template) { 16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson executionStack.add(template); 16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void popExecutionContext() { 17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson executionStack.remove(executionStack.size() - 1); 17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void setCurrentPosition(int line, int column) { 17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: Should these be saved in executionStack as part 17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // of pushExecutionContext? 18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.line = line; 18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.column = column; 18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void registerMacro(String name, Macro macro) { 18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson macros.put(name, macro); 18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Macro findMacro(String name) { 19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Macro macro = macros.get(name); 19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (macro == null) { 19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("No such macro: " + name); 19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return macro; 19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public DataContext getDataContext() { 20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return dataContext; 20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public ResourceLoader getResourceLoader() { 20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return resourceLoader; 20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public AutoEscapeOptions getAutoEscapeOptions() { 21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return autoEscapeOptions; 21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public EscapeMode getAutoEscapeMode() { 21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isRuntimeAutoEscaping() || (currentEscaper != null)) { 21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return EscapeMode.ESCAPE_NONE; 21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return autoEscapeMode; 21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void pushAutoEscapeMode(EscapeMode mode) { 22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isRuntimeAutoEscaping()) { 22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException( 22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson "cannot call pushAutoEscapeMode while runtime auto escaping is in progress"); 22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeStack.add(autoEscapeMode); 22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeMode = mode; 23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void popAutoEscapeMode() { 23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int len = autoEscapeStack.size(); 23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (len == 0) { 23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("No more auto escaping modes to pop."); 23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeMode = autoEscapeStack.remove(autoEscapeStack.size() - 1); 23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean isRuntimeAutoEscaping() { 24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return autoEscapeContext != null; 24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@inheritDoc} 24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws JSilverInterpreterException if startRuntimeAutoEscaping is called while runtime 25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * autoescaping is already in progress. 25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void startRuntimeAutoEscaping() { 25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isRuntimeAutoEscaping()) { 25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("startRuntimeAutoEscaping() is not re-entrant at " 25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + getCurrentResourceName()); 25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!autoEscapeMode.equals(EscapeMode.ESCAPE_NONE)) { 25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: Get the resourceName as a parameter to this function 26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext = new AutoEscapeContext(autoEscapeMode, getCurrentResourceName()); 26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson startingAutoEscapeState = autoEscapeContext.getCurrentState(); 26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext = null; 26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String getCurrentResourceName() { 26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (executionStack.size() == 0) { 26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return ""; 27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return executionStack.get(executionStack.size() - 1).getDisplayName(); 27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void stopRuntimeAutoEscaping() { 27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (autoEscapeContext != null) { 27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!startingAutoEscapeState.equals(autoEscapeContext.getCurrentState())) { 27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // We do not allow a macro call to change context of the rest of the template. 28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Since the rest of the template has already been auto-escaped at parse time 28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // with the assumption that the macro call will not modify the context. 28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverAutoEscapingException("Macro starts in context " + startingAutoEscapeState 28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + " but ends in different context " + autoEscapeContext.getCurrentState(), 28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext.getResourceName()); 28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeContext = null; 28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean pushIncludeStackEntry(String templateName) { 29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return includeStack.push(templateName); 29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean popIncludeStackEntry(String templateName) { 29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return templateName.equals(includeStack.pop()); 29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Iterable<String> getIncludedTemplateNames() { 30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return includeStack; 30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 305