1 package server; 2 3 import java.util.BitSet; 4 import java.util.HashMap; 5 6 import structures.ByteBuilder; 7 8 public class PercentEncoding { 9 containsSpecialSymbol(String s)10 public static boolean containsSpecialSymbol(String s){ 11 if(s==null){return false;} 12 for(int i=0, max=s.length(); i<max; i++){ 13 char c=s.charAt(i); 14 if(isSpecial.get(c)){ 15 // System.err.print("b"); 16 return true;} 17 } 18 // System.err.print("c"); 19 return false; 20 } 21 containsCommonSymbol(String s)22 public static boolean containsCommonSymbol(String s){ 23 if(s==null){return false;} 24 for(int i=0, max=s.length(); i<max; i++){ 25 char c=s.charAt(i); 26 if(isCommon.get(c)){return true;} 27 } 28 return false; 29 } 30 symbolToCode(String s)31 public static String symbolToCode(String s){ 32 // System.err.print("a"); 33 if(!containsSpecialSymbol(s)){return s;} 34 // System.err.print("d"); 35 ByteBuilder bb=new ByteBuilder(); 36 for(int i=0, max=s.length(); i<max; i++){ 37 char c=s.charAt(i); 38 String code=symbolToCodeArray[c]; 39 if(code!=null){ 40 // System.err.print("e("+code+")"); 41 bb.append(code); 42 }else{ 43 // System.err.print("f"); 44 bb.append(c); 45 } 46 } 47 // System.err.println("g"); 48 // System.err.println(bb); 49 return bb.toString(); 50 } 51 commonSymbolToCode(String s)52 public static String commonSymbolToCode(String s){ 53 if(!containsCommonSymbol(s)){return s;} 54 ByteBuilder bb=new ByteBuilder(); 55 for(int i=0, max=s.length(); i<max; i++){ 56 char c=s.charAt(i); 57 if(isCommon.get(c)){ 58 String code=symbolToCodeArray[c]; 59 assert(code!=null); 60 bb.append(code); 61 }else{ 62 bb.append(c); 63 } 64 } 65 return bb.toString(); 66 } 67 parseCode(String s, int start)68 private static int parseCode(String s, int start){ 69 if(s==null || start+2>=s.length()){return -1;} 70 assert(s.charAt(start)=='%'); 71 int sum=0; 72 for(int i=start+1; i<=start+2; i++){ 73 sum=sum<<4; 74 final char c=s.charAt(i); 75 if(c>='0' && c<='9'){ 76 sum=sum+(c-'0'); 77 }else if(c>='A' && c<'F'){ 78 sum=sum+(10+c-'A'); 79 }else{ 80 return -1; 81 } 82 } 83 return sum; 84 } 85 codeToSymbol(String s)86 public static String codeToSymbol(String s){ 87 int idx=s.indexOf('%'); 88 if(idx<0){return s;} 89 90 ByteBuilder bb=new ByteBuilder(s.length()); 91 for(int i=0; i<s.length(); i++){ 92 char c=s.charAt(i); 93 if(c=='%'){ 94 int sym=parseCode(s, i); 95 if(sym<0){bb.append(c);} 96 else{ 97 bb.append((char)sym); 98 i+=2;//Skip next 2 characters 99 } 100 }else{bb.append(c);} 101 } 102 return (bb.length()==s.length() ? s : bb.toString()); 103 } 104 makeCodeToSymbolMap()105 private static HashMap<String, String> makeCodeToSymbolMap() { 106 HashMap<String, String> map=new HashMap<String, String>(129); 107 assert(reservedSymbol.length==reservedCode.length); 108 assert(commonSymbol.length==commonCode.length); 109 for(int i=0; i<reservedSymbol.length; i++){ 110 map.put(reservedCode[i], reservedSymbol[i]); 111 } 112 for(int i=0; i<commonSymbol.length; i++){ 113 map.put(commonCode[i], commonSymbol[i]); 114 } 115 return map; 116 } 117 makeSymbolToCodeMap()118 private static HashMap<String, String> makeSymbolToCodeMap() { 119 HashMap<String, String> map=new HashMap<String, String>(257); 120 assert(reservedSymbol.length==reservedCode.length); 121 assert(commonSymbol.length==commonCode.length); 122 for(int i=0; i<reservedSymbol.length; i++){ 123 map.put(reservedSymbol[i], reservedCode[i]); 124 } 125 for(int i=0; i<commonSymbol.length; i++){ 126 map.put(commonSymbol[i], commonCode[i]); 127 } 128 return map; 129 } 130 makeSymbolToCodeArray()131 private static String[] makeSymbolToCodeArray() { 132 final String[] array=new String[128]; 133 for(int i=0; i<reservedSymbol.length; i++){ 134 String s=reservedSymbol[i]; 135 String c=reservedCode[i]; 136 array[s.charAt(0)]=c; 137 } 138 for(int i=0; i<commonSymbol.length; i++){ 139 String s=commonSymbol[i]; 140 String c=commonCode[i]; 141 array[s.charAt(0)]=c; 142 } 143 return array; 144 } 145 makeBitSet(String[]....matrix)146 private static final BitSet makeBitSet(String[]...matrix){ 147 BitSet bs=new BitSet(128); 148 for(String[] array : matrix){ 149 for(String s : array){ 150 char c=s.charAt(0); 151 bs.set(c); 152 } 153 } 154 return bs; 155 } 156 157 //See https://en.wikipedia.org/wiki/Percent-encoding 158 public static final String[] reservedSymbol=new String[] { 159 "!", "#", "$", "&", "'", "(", ")", "*", "+", ",", "/", ":", ";", "=", "?", "@", "[", "]" 160 }; 161 162 public static final String[] reservedCode=new String[] { 163 "%21", "%23", "%24", "%26", "%27", "%28", "%29", "%2A", "%2B", "%2C", "%2F", "%3A", "%3B", "%3D", "%3F", "%40", "%5B", "%5D" 164 }; 165 166 public static final String[] commonSymbol=new String[] { 167 "\n", " ", "\"", "%", "<", ">", "\\", "|", 168 }; 169 170 public static final String[] commonCode=new String[] { 171 "%0A", "%20", "%22", "%25", "%3C", "%3E", "%5C", "%7C" 172 }; 173 174 private static final BitSet isSpecial=makeBitSet(reservedSymbol, commonSymbol); 175 private static final BitSet isCommon=makeBitSet(commonSymbol); 176 177 // public static final HashMap<String, String> codeToSymbolMap=makeCodeToSymbolMap(); 178 // public static final HashMap<String, String> symbolToCodeMap=makeSymbolToCodeMap(); 179 public static final String[] symbolToCodeArray=makeSymbolToCodeArray(); 180 181 /** Don't print caught exceptions */ 182 public static boolean suppressErrors=false; 183 184 } 185