public static String decodeIdentifier(String str) {
return decode(str.getBytes(), (byte) '$', true);
}
-
+
+ /**
+ * Escape any of the following characters: <code><>:"/\|?*</code> with %nn.
+ *
+ * @param str a file name, not a full file path
+ * @return original string or escaped file name if encoding is needed
+ */
+ public static String encodeFilename2(String str) {
+ return encodeFilename2(str, '%');
+ }
+
+ private static String encodeFilename2(String str, char escapeChar) {
+ // First calculate the length
+ int originalLength = str.length();
+ int length = originalLength;
+ for (int i = 0; i < originalLength; ++i) {
+ char c = str.charAt(i);
+ if (c < 128 && fileNameEncodeTable[(int) c] == -1)
+ length += 2;
+ }
+
+ if (length == originalLength)
+ return str;
+
+ char[] result = new char[length];
+ int pos = 0;
+ for (int i = 0; i < originalLength; ++i) {
+ char c = str.charAt(i);
+ int ic = c;
+ if (c >= 128) {
+ // Never escape any non-ASCII characters. Those should work.
+ result[pos++] = c;
+ } else {
+ int ec = fileNameEncodeTable[ic];
+ if (ec >= 0) {
+ result[pos++] = (char) ec;
+ } else {
+ result[pos++] = escapeChar;
+ result[pos++] = Character.forDigit(ic >> 4, 16);
+ result[pos++] = Character.forDigit(ic & 15, 16);
+ }
+ }
+ }
+ return new String(result);
+ }
+
+ static final int[] fileNameEncodeTable = new int[128]; // for UTF-16 non-bijection filenames
+
+ static {
+ for (int i = 0; i < fileNameEncodeTable.length; ++i) {
+ if (i < 32) {
+ // Control characters are all in need of escapes
+ fileNameEncodeTable[i] = -1;
+ } else {
+ switch ((char) i) {
+ // Denied characters in windows file names
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ case '<': case '>': case ':': case '"': case '/': case '\\': case '|': case '?': case '*':
+ fileNameEncodeTable[i] = -1;
+ break;
+ default:
+ fileNameEncodeTable[i] = i;
+ break;
+ }
+ }
+ }
+ }
+
}