Integrate properties parser into boot properties extension
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user