Integrate properties parser into boot properties extension

This commit is contained in:
BoykoAlex
2016-10-28 17:17:39 -04:00
parent 28fed6ffcb
commit 146ae7ee61
18 changed files with 1498 additions and 60 deletions

View File

@@ -31,6 +31,7 @@ import org.springframework.ide.vscode.java.properties.parser.Parser;
import org.springframework.ide.vscode.java.properties.parser.Problem;
import org.springframework.ide.vscode.java.properties.parser.ProblemCodes;
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst;
import org.springframework.ide.vscode.java.properties.parser.PropertiesFileEscapes;
import com.google.common.collect.ImmutableList;
@@ -230,7 +231,12 @@ public class AntlrParser implements Parser {
@Override
public String decode() {
return context.getText().replace("\\:", ":").replace("\\=", "=");
// return context.getText().replace("\\:", ":").replace("\\=", "=");
try {
return PropertiesFileEscapes.unescape(context.getText());
} catch (Exception e) {
return context.getText().replace("\\:", ":").replace("\\=", "=");
}
}
}
@@ -249,8 +255,13 @@ public class AntlrParser implements Parser {
private void init() {
// Remove the separator, if it exists
value = context.getText().replaceAll("^\\s*[:=]?\\s*", "");
// Remove all escaped line breaks with trailing spaces
// Remove all escaped line breaks with trailing spaces
decoded = value.replaceAll("\\\\(\r?\n|\r)[ \t\f]*", "");
try {
decoded = PropertiesFileEscapes.unescape(decoded);
} catch (Exception e) {
// ignore
}
}
@Override

View File

@@ -0,0 +1,317 @@
package org.springframework.ide.vscode.java.properties.parser;
/**
* Helper class to convert between Java chars and the escaped form that must be used in .properties
* files.
*
* @since 3.7
*/
public class PropertiesFileEscapes {
private static final char[] HEX_DIGITS= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static char toHex(int halfByte) {
return HEX_DIGITS[(halfByte & 0xF)];
}
/**
* Returns the decimal value of the Hex digit, or -1 if the digit is not a valid Hex digit.
*
* @param digit the Hex digit
* @return the decimal value of digit, or -1 if digit is not a valid Hex digit.
*/
private static int getHexDigitValue(char digit) {
switch (digit) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return digit - '0';
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return 10 + digit - 'a';
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return 10 + digit - 'A';
default:
return -1;
}
}
/**
* Convert a Java char to the escaped form that must be used in .properties files.
*
* @param c the Java char
* @return escaped string
*/
public static String escape(char c) {
return escape(c, true, true, true);
}
/**
* Convert characters in a Java string to the escaped form that must be used in .properties
* files.
*
* @param s the Java string
* @param escapeWhitespaceChars if <code>true</code>, escape whitespace characters
* @param escapeBackslash if <code>true</code>, escape backslash characters
* @param escapeUnicodeChars if <code>true</code>, escape unicode characters
* @return escaped string
*/
public static String escape(String s, boolean escapeWhitespaceChars, boolean escapeBackslash, boolean escapeUnicodeChars) {
StringBuffer sb= new StringBuffer(s.length());
int length= s.length();
for (int i= 0; i < length; i++) {
char c= s.charAt(i);
sb.append(escape(c, escapeWhitespaceChars, escapeBackslash, escapeUnicodeChars));
}
return sb.toString();
}
/**
* Convert a Java char to the escaped form that must be used in .properties files.
*
* @param c the Java char
* @param escapeWhitespaceChars if <code>true</code>, escape whitespace characters
* @param escapeBackslash if <code>true</code>, escape backslash characters
* @param escapeUnicodeChars if <code>true</code>, escape unicode characters
* @return escaped string
*/
public static String escape(char c, boolean escapeWhitespaceChars, boolean escapeBackslash, boolean escapeUnicodeChars) {
switch (c) {
case '\t':
return escapeWhitespaceChars ? "\\t" : "\t"; //$NON-NLS-1$//$NON-NLS-2$
case '\n':
return escapeWhitespaceChars ? "\\n" : "\n"; //$NON-NLS-1$//$NON-NLS-2$
case '\f':
return escapeWhitespaceChars ? "\\f" : "\r"; //$NON-NLS-1$//$NON-NLS-2$
case '\r':
return escapeWhitespaceChars ? "\\r" : "\r"; //$NON-NLS-1$//$NON-NLS-2$
case '\\':
return escapeBackslash ? "\\\\" : "\\"; //$NON-NLS-1$ //$NON-NLS-2$
default:
if (escapeUnicodeChars && ((c < 0x0020) || (c > 0x007e && c <= 0x00a0) || (c > 0x00ff))) {
//NBSP (0x00a0) is escaped to differentiate from normal space character
return new StringBuffer()
.append('\\')
.append('u')
.append(toHex((c >> 12) & 0xF))
.append(toHex((c >> 8) & 0xF))
.append(toHex((c >> 4) & 0xF))
.append(toHex(c & 0xF)).toString();
} else
return String.valueOf(c);
}
}
/**
* Convert an escaped string to a string composed of Java characters.
*
* @param s the escaped string
* @return string composed of Java characters
* @throws CoreException if the escaped string has a malformed \\uxxx sequence
*/
public static String unescape(String s) throws Exception {
boolean isValidEscapedString= true;
if (s == null)
return null;
char aChar;
int len= s.length();
StringBuffer outBuffer= new StringBuffer(len);
for (int x= 0; x < len;) {
aChar= s.charAt(x++);
if (aChar == '\\') {
if (x > len - 1) {
return outBuffer.toString(); // silently ignore the \
}
aChar= s.charAt(x++);
if (aChar == 'u') {
// Read the xxxx
int value= 0;
if (x > len - 4) {
throw new Exception("Malformed encoding for properties file");
}
StringBuffer buf= new StringBuffer("\\u"); //$NON-NLS-1$
int digit= 0;
for (int i= 0; i < 4; i++) {
aChar= s.charAt(x++);
digit= getHexDigitValue(aChar);
if (digit == -1) {
isValidEscapedString= false;
x--;
break;
}
value= (value << 4) + digit;
buf.append(aChar);
}
outBuffer.append(digit == -1 ? buf.toString() : String.valueOf((char)value));
} else if (aChar == 't') {
outBuffer.append('\t');
} else if (aChar == 'n') {
outBuffer.append('\n');
} else if (aChar == 'f') {
outBuffer.append('\f');
} else if (aChar == 'r') {
outBuffer.append('\r');
} else {
outBuffer.append(aChar); // silently ignore the \
}
} else
outBuffer.append(aChar);
}
if (isValidEscapedString) {
return outBuffer.toString();
} else {
throw new Exception("Malformed encoding for properties file");
}
}
/**
* Unescape backslash characters in a string.
*
* @param s the escaped string
* @return string with backslash characters unescaped
*/
public static String unescapeBackslashes(String s) {
if (s == null)
return null;
char c;
int length= s.length();
StringBuffer outBuffer= new StringBuffer(length);
for (int i= 0; i < length;) {
c= s.charAt(i++);
if (c == '\\') {
c= s.charAt(i++);
}
outBuffer.append(c);
}
return outBuffer.toString();
}
/**
* Tests if the given text contains any invalid escape sequence.
*
* @param text the text
* @return <code>true</code> if text contains an invalid escape sequence, <code>false</code>
* otherwise
*/
public static boolean containsInvalidEscapeSequence(String text) {
try {
//check for invalid unicode escapes
unescape(text);
} catch (Exception e) {
return true;
}
int length= text.length();
for (int i= 0; i < length; i++) {
char c= text.charAt(i);
if (c == '\\') {
if (i < length - 1) {
char nextC= text.charAt(i + 1);
switch (nextC) {
case 't':
case 'n':
case 'f':
case 'r':
case 'u':
case '\n':
case '\r':
case '=':
case ':':
break;
case '\\':
i++;
break;
default:
return true;
}
} else {
return true;
}
}
}
return false;
}
/**
* Tests if the given text contains an unescaped backslash character.
*
* @param text the text
* @return <code>true</code> if text contains an unescaped backslash character,
* <code>false</code> otherwise
*/
public static boolean containsUnescapedBackslash(String text) {
int length= text.length();
for (int i= 0; i < length; i++) {
char c= text.charAt(i);
if (c == '\\') {
if (i < length - 1) {
char nextC= text.charAt(i + 1);
switch (nextC) {
case '\\':
i++;
break;
default:
return true;
}
} else {
return true;
}
}
}
return false;
}
/**
* Tests if the given text contains only escaped backslash characters and no unescaped backslash
* character.
*
* @param text the text
* @return <code>true</code> if text contains only escaped backslash characters,
* <code>false</code> otherwise
*/
public static boolean containsEscapedBackslashes(String text) {
boolean result= false;
int length= text.length();
for (int i= 0; i < length; i++) {
char c= text.charAt(i);
if (c == '\\') {
if (i < length - 1) {
char nextC= text.charAt(i + 1);
switch (nextC) {
case '\\':
i++;
result= true;
break;
default:
return false;
}
} else {
return false;
}
}
}
return result;
}
}