]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Added URIUtil.encodeFilename2 which encodes only necessary characters. 25/625/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 14 Jun 2017 16:22:30 +0000 (19:22 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 14 Jun 2017 16:27:37 +0000 (19:27 +0300)
The new method uses the same '%' URI style encoding as
URIUtil.encodeFilename but encodes only characters that cannot be
present in Windows file names, i.e. the following: <>:"/\|?*

This method can be used to convert arbitrary user-given names to valid
file names in wizards etc.

refs #7301

Change-Id: Ia7e264e5304ff0533376c73f5ae9312e197ccf15

bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java

index b1e5b8ec4da5cfdc5d41cc4f5242e01294ae7a43..0bfc3b1b12c52e543001fcbcf74d0d96bc7c4e7e 100644 (file)
@@ -221,5 +221,72 @@ public final class URIUtil {
     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;
+                }
+            }
+        }
+    }
+
 }