|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| CharConverter.java | 29.2% | 18.9% | 42.9% | 21.9% |
|
||||||||||||||
| 1 | /*BEGIN_COPYRIGHT_BLOCK | |
| 2 | * | |
| 3 | * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu) | |
| 4 | * All rights reserved. | |
| 5 | * | |
| 6 | * Redistribution and use in source and binary forms, with or without | |
| 7 | * modification, are permitted provided that the following conditions are met: | |
| 8 | * * Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * * Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the | |
| 14 | * names of its contributors may be used to endorse or promote products | |
| 15 | * derived from this software without specific prior written permission. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
| 21 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 24 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| 25 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 26 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 28 | * | |
| 29 | * This software is Open Source Initiative approved Open Source Software. | |
| 30 | * Open Source Initative Approved is a trademark of the Open Source Initiative. | |
| 31 | * | |
| 32 | * This file is part of DrJava. Download the current version of this project | |
| 33 | * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/ | |
| 34 | * | |
| 35 | * END_COPYRIGHT_BLOCK*/ | |
| 36 | ||
| 37 | package edu.rice.cs.javalanglevels; | |
| 38 | ||
| 39 | /** | |
| 40 | * A class full of static methods for escaping/unescaping characters. | |
| 41 | * It's abstract because it should not be instantiated. | |
| 42 | */ | |
| 43 | public abstract class CharConverter { | |
| 44 | /** | |
| 45 | * Escapes the given char to be suitable for writing out in | |
| 46 | * a Java char or String literal. | |
| 47 | * | |
| 48 | * @param c Character to escape | |
| 49 | * @return A string consisting of c, properly escaped for use | |
| 50 | * inside a Java char or String literal. There are no | |
| 51 | * quotation marks around the result. | |
| 52 | */ | |
| 53 | 0 | public static String escapeChar(char c) { |
| 54 | 0 | StringBuffer buf = new StringBuffer(); |
| 55 | 0 | escapeChar(c, buf); |
| 56 | 0 | return buf.toString(); |
| 57 | } | |
| 58 | ||
| 59 | /** | |
| 60 | * Escapes the given char to be suitable for writing out in | |
| 61 | * a Java char or String literal. | |
| 62 | * | |
| 63 | * @param c Character to escape | |
| 64 | * @param buf StringBuffer where the result is written out | |
| 65 | */ | |
| 66 | 0 | public static void escapeChar(char c, StringBuffer buf) { |
| 67 | 0 | switch (c) { |
| 68 | 0 | case '\n': buf.append("\\n"); break; |
| 69 | 0 | case '\t': buf.append("\\t"); break; |
| 70 | 0 | case '\b': buf.append("\\b"); break; |
| 71 | 0 | case '\r': buf.append("\\r"); break; |
| 72 | 0 | case '\f': buf.append("\\f"); break; |
| 73 | 0 | case '\\': buf.append("\\\\"); break; |
| 74 | 0 | case '\'': buf.append("\\\'"); break; |
| 75 | 0 | case '\"': buf.append("\\\""); break; |
| 76 | 0 | default: |
| 77 | // unicode escape all non-ascii | |
| 78 | 0 | if ((c < 32) || (c > 127)) { |
| 79 | 0 | String hex = Integer.toHexString(c); |
| 80 | 0 | buf.append("\\u"); |
| 81 | ||
| 82 | 0 | for (int i = hex.length(); i < 4; i++) { |
| 83 | 0 | buf.append('0'); |
| 84 | } | |
| 85 | ||
| 86 | 0 | buf.append(hex); |
| 87 | } | |
| 88 | else { | |
| 89 | 0 | buf.append(c); |
| 90 | } | |
| 91 | 0 | break; |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | /** | |
| 96 | * Escapes the given String to be suitable for writing out as a | |
| 97 | * Java String literal. | |
| 98 | * | |
| 99 | * @param s String to escape | |
| 100 | * @return A string consisting of s, properly escaped for use | |
| 101 | * inside a Java String literal. There are no | |
| 102 | * quotation marks around the result. | |
| 103 | */ | |
| 104 | 0 | public static String escapeString(String s) { |
| 105 | 0 | StringBuffer buf = new StringBuffer(); |
| 106 | ||
| 107 | 0 | for (int i = 0; i < s.length(); i++) { |
| 108 | 0 | escapeChar(s.charAt(i), buf); |
| 109 | } | |
| 110 | ||
| 111 | 0 | return buf.toString(); |
| 112 | } | |
| 113 | ||
| 114 | /** | |
| 115 | * Unescapes the given string, escaped as it would be in Java source, | |
| 116 | * to a single char. Note that this does not handle unicode escapes | |
| 117 | * of the form \ uXXXX; these are expected to have already been processed | |
| 118 | * out of the input string. The only escapes that are handled are octal escapes | |
| 119 | * and \n \t \b \r \f \\ \' \". | |
| 120 | * | |
| 121 | * @param in String containing (possibly) escaped character, without quotes | |
| 122 | * @return char value of the input string, unescaped. | |
| 123 | */ | |
| 124 | 7 | public static char unescapeChar(String in) { |
| 125 | 7 | StringBuffer buf = new StringBuffer(); |
| 126 | 7 | int endPos = unescapeString(in, 0, buf); |
| 127 | 7 | if (endPos < in.length()) { |
| 128 | 0 | throw new IllegalArgumentException((in.length() - endPos) + " trailing" + |
| 129 | " characters at the end of character"+ | |
| 130 | " literal '" + in + "'"); | |
| 131 | } | |
| 132 | ||
| 133 | 7 | return buf.charAt(0); |
| 134 | } | |
| 135 | ||
| 136 | /** | |
| 137 | * Unescapes the given string, escaped as it would be in Java source, | |
| 138 | * to a String. Note that this does not handle unicode escapes | |
| 139 | * of the form \ uXXXX; these are expected to have already been processed | |
| 140 | * out of the input string. The only escapes that are handled are octal escapes | |
| 141 | * and \n \t \b \r \f \\ \' \". | |
| 142 | * | |
| 143 | * @param in String containing (possibly) escaped characters, without quotes | |
| 144 | * @return Unescaped string value of the input string | |
| 145 | */ | |
| 146 | 66 | public static String unescapeString(String in) { |
| 147 | // short circuit "" to allow the rest to assume != "". | |
| 148 | 66 | if (in.length() == 0) { |
| 149 | 2 | return in; |
| 150 | } | |
| 151 | ||
| 152 | 64 | StringBuffer buf = new StringBuffer(); |
| 153 | 64 | int nextStart = 0; |
| 154 | ||
| 155 | 64 | while (nextStart < in.length()) { |
| 156 | 867 | nextStart = unescapeString(in, nextStart, buf); |
| 157 | } | |
| 158 | ||
| 159 | 64 | return buf.toString(); |
| 160 | } | |
| 161 | ||
| 162 | /* | |
| 163 | public static char unescapeChar(String in) { | |
| 164 | if (in.length() == 1) { | |
| 165 | return s.charAt(0); | |
| 166 | } | |
| 167 | else if ((in.length() > 1) && (in.charAt(0) == '\\')) { | |
| 168 | switch (in.charAt(1)) { | |
| 169 | case 'n': return '\n'; | |
| 170 | case 't': return '\t'; | |
| 171 | case 'b': return '\b'; | |
| 172 | case 'r': return '\r'; | |
| 173 | case 'f': return '\f'; | |
| 174 | case '\\': return '\\'; | |
| 175 | case '\'': return '\''; | |
| 176 | case '\"': return '\"'; | |
| 177 | } | |
| 178 | ||
| 179 | // deal with octal escapes | |
| 180 | String afterBackslash = in.substring(1); | |
| 181 | try { | |
| 182 | int charValue = Integer.parseInt(afterBackslash, 8); | |
| 183 | if ((charValue > Character.MAX_VALUE) || (charValue < Character.MIN_VALUE)) { | |
| 184 | throw new RuntimeException("octal escaped character out of range: " + in); | |
| 185 | } | |
| 186 | ||
| 187 | return (char) charValue; | |
| 188 | } | |
| 189 | catch (NumberFormatException e) { | |
| 190 | throw new RuntimeException("multi-char char literal invalid! value=" + in); | |
| 191 | } | |
| 192 | } | |
| 193 | else { | |
| 194 | throw new RuntimeException("multi-character char literal doesn't start with \\! value=" + in); | |
| 195 | } | |
| 196 | } | |
| 197 | */ | |
| 198 | ||
| 199 | /** | |
| 200 | * Unescapes one character in the given string, escaped as it would be in | |
| 201 | * Java source, to a String. Note that this does not handle unicode escapes | |
| 202 | * of the form \ uXXXX; these are expected to have already been processed | |
| 203 | * out of the input string. The only escapes that are handled are octal escapes | |
| 204 | * and \n \t \b \r \f \\ \' \". | |
| 205 | * | |
| 206 | * @param in String containing (possibly) escaped characters | |
| 207 | * @param startPos Starting position of the next character to unescape | |
| 208 | * @param out StringBuffer to write out the unescaped character to. | |
| 209 | * | |
| 210 | * @return Position after the end of the parsed character | |
| 211 | */ | |
| 212 | 874 | public static int unescapeString(final String in, |
| 213 | final int startPos, | |
| 214 | final StringBuffer out) | |
| 215 | { | |
| 216 | 874 | char first = in.charAt(startPos); |
| 217 | ||
| 218 | 874 | if (first != '\\') { |
| 219 | 873 | out.append(first); |
| 220 | 873 | return startPos + 1; |
| 221 | } | |
| 222 | ||
| 223 | 1 | char second = in.charAt(startPos + 1); |
| 224 | ||
| 225 | 1 | switch (second) { |
| 226 | 0 | case 'n': out.append('\n'); return startPos + 2; |
| 227 | 0 | case 't': out.append('\t'); return startPos + 2; |
| 228 | 0 | case 'b': out.append('\b'); return startPos + 2; |
| 229 | 0 | case 'r': out.append('\r'); return startPos + 2; |
| 230 | 0 | case 'f': out.append('\f'); return startPos + 2; |
| 231 | 1 | case '\\': out.append('\\'); return startPos + 2; |
| 232 | 0 | case '\'': out.append('\''); return startPos + 2; |
| 233 | 0 | case '\"': out.append('\"'); return startPos + 2; |
| 234 | } | |
| 235 | ||
| 236 | // The only cases left to deal with are octal escapes or invalid. | |
| 237 | 0 | if (_isOctalDigit(second)) { |
| 238 | // If the first digit is < 4, there could be three octal digits. | |
| 239 | // Otherwise there can be only two. | |
| 240 | 0 | int maxDigits; |
| 241 | 0 | if (second < '4') { |
| 242 | 0 | maxDigits = 3; |
| 243 | } | |
| 244 | else { | |
| 245 | 0 | maxDigits = 2; |
| 246 | } | |
| 247 | ||
| 248 | 0 | StringBuffer octal = new StringBuffer(maxDigits); |
| 249 | 0 | octal.append(second); |
| 250 | ||
| 251 | 0 | int nextDigitPos = startPos + 2; |
| 252 | 0 | while ((octal.length() < maxDigits) && (nextDigitPos < in.length())) { |
| 253 | 0 | char nextChar = in.charAt(nextDigitPos); |
| 254 | 0 | if (_isOctalDigit(nextChar)) { |
| 255 | 0 | octal.append(nextChar); |
| 256 | 0 | nextDigitPos++; |
| 257 | } | |
| 258 | else { // not an octal digit, so our work here is done. | |
| 259 | 0 | break; |
| 260 | } | |
| 261 | } | |
| 262 | ||
| 263 | 0 | try { |
| 264 | 0 | int charValue = Integer.parseInt(octal.toString(), 8); |
| 265 | 0 | if ((charValue > Character.MAX_VALUE) || (charValue < Character.MIN_VALUE)) { |
| 266 | 0 | throw new IllegalArgumentException("Octal escape beginning at " + |
| 267 | "position " + startPos + " out of range: " + in); | |
| 268 | } | |
| 269 | ||
| 270 | 0 | out.append((char) charValue); |
| 271 | 0 | return nextDigitPos; |
| 272 | } | |
| 273 | catch (NumberFormatException e) { | |
| 274 | 0 | throw new RuntimeException("Impossible to occur, but number format exception in octal escape!"); |
| 275 | } | |
| 276 | } | |
| 277 | else { | |
| 278 | 0 | throw new IllegalArgumentException("Invalid escape sequence at position "+ |
| 279 | startPos + ": " + in); | |
| 280 | } | |
| 281 | } | |
| 282 | ||
| 283 | 0 | private static boolean _isOctalDigit(char c) { |
| 284 | 0 | return ((c >= '0') && (c <= '7')); |
| 285 | } | |
| 286 | } |
|
||||||||||