Home | History | Annotate | Download | only in escape
      1 /*
      2  * Copyright (C) 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.clearsilver.jsilver.functions.escape;
     18 
     19 import com.google.clearsilver.jsilver.functions.TextFilter;
     20 
     21 import java.io.IOException;
     22 
     23 /**
     24  * This function will be used to sanitize variables in 'style' attributes. It strips out any
     25  * characters that are not part of a whitelist of safe characters. This replicates the autoescaping
     26  * behavior of Clearsilver.
     27  *
     28  * It does not extend SimpleEscapingFunction because SimpleEscapingFunction requires a blacklist of
     29  * characters to escape. The StyleAttrEscapeFunction instead applies a whitelist, and strips out any
     30  * characters not in the whitelist.
     31  */
     32 public class StyleEscapeFunction implements TextFilter {
     33 
     34   private static final boolean[] UNQUOTED_VALID_CHARS;
     35   private static final boolean[] VALID_CHARS;
     36   private static final int MAX_CHARS = 0x80;
     37 
     38   static {
     39     // Allow characters likely to occur inside a style property value.
     40     // Refer http://www.w3.org/TR/CSS21/ for more details.
     41     String SPECIAL_CHARS = "_.,!#%- ";
     42     String UNQUOTED_SPECIAL_CHARS = "_.,!#%-";
     43 
     44     VALID_CHARS = new boolean[MAX_CHARS];
     45     UNQUOTED_VALID_CHARS = new boolean[MAX_CHARS];
     46 
     47     for (int n = 0; n < MAX_CHARS; n++) {
     48       VALID_CHARS[n] = false;
     49       UNQUOTED_VALID_CHARS[n] = false;
     50 
     51       if (Character.isLetterOrDigit(n)) {
     52         VALID_CHARS[n] = true;
     53         UNQUOTED_VALID_CHARS[n] = true;
     54       } else {
     55         if (SPECIAL_CHARS.indexOf(n) != -1) {
     56           VALID_CHARS[n] = true;
     57         }
     58 
     59         if (UNQUOTED_SPECIAL_CHARS.indexOf(n) != -1) {
     60           UNQUOTED_VALID_CHARS[n] = true;
     61         }
     62       }
     63     }
     64   }
     65 
     66   private final boolean[] validChars;
     67 
     68   /**
     69    * isUnquoted should be true if the function is escaping a string that will appear inside an
     70    * unquoted style attribute.
     71    *
     72    */
     73   public StyleEscapeFunction(boolean isUnquoted) {
     74     if (isUnquoted) {
     75       validChars = UNQUOTED_VALID_CHARS;
     76     } else {
     77       validChars = VALID_CHARS;
     78     }
     79   }
     80 
     81   public void filter(String in, Appendable out) throws IOException {
     82     for (char c : in.toCharArray()) {
     83       if (c < MAX_CHARS && validChars[c]) {
     84         out.append(c);
     85       } else if (c >= MAX_CHARS) {
     86         out.append(c);
     87       }
     88     }
     89   }
     90 
     91   public void dumpInfo() {
     92     for (int i = 0; i < MAX_CHARS; i++) {
     93       System.out.println(i + "(" + (char) i + ")" + " :" + VALID_CHARS[i]);
     94     }
     95   }
     96 }
     97