JCRVLT-49 support node names only differing in casing on case
insensitive file systems

WIP
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
index a570690..33a3d9a 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
@@ -100,9 +100,7 @@
                  case '/':
                  case'?':
                  case'%':
-                     buf.append('%');
-                     buf.append(Character.forDigit(c / 16, 16));
-                     buf.append(Character.forDigit(c % 16, 16));
+                     addEscapedCharacter(buf, c);
                      break;
                  default:
                      buf.append(c);
@@ -115,6 +113,12 @@
         }
     }
 
+    public static void addEscapedCharacter(StringBuilder buf, char c) {
+        buf.append('%');
+        buf.append(Character.forDigit(c / 16, 16));
+        buf.append(Character.forDigit(c % 16, 16));
+    }
+
     /**
      * Returns the platform path for the given repository one.
      * @param repoPath the repository path
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
index 27fff62..d387b71 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("2.10.0")
+@Version("2.11.0")
 package org.apache.jackrabbit.vault.util;
 
 import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
index c5014e5..4412c26 100644
--- a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
+++ b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltDirectory.java
@@ -18,11 +18,16 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Optional;
 import java.util.Set;
+import java.util.function.Predicate;
 
 import javax.jcr.RepositoryException;
 
@@ -33,6 +38,7 @@
 import org.apache.jackrabbit.vault.util.Constants;
 import org.apache.jackrabbit.vault.util.FileInputSource;
 import org.apache.jackrabbit.vault.util.LineOutputStream;
+import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.jackrabbit.vault.vlt.actions.Action;
 import org.apache.jackrabbit.vault.vlt.meta.MetaDirectory;
 import org.apache.jackrabbit.vault.vlt.meta.VltEntries;
@@ -76,6 +82,78 @@
         init();
     }
 
+    /** 
+     * Escapes the given name according to the file escaping rules in case a conflicting file name (e.g. just differ by case in case-ignoring filesystem) exists
+     * in the current directory.
+     * 
+     * @param name
+     * @return
+     */
+    String escapeToMakeUnique(String name) {
+        File newFile = new File(dir, name);
+        Predicate<VltFile> sameFilePredicate = f -> { 
+            try {
+                return Files.isSameFile(f.getFile().toPath(), newFile.toPath());
+            } catch (NoSuchFileException e) {
+                // ignore
+                return false;
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+        Optional<VltFile> conflictingFile = getFiles().stream().filter(sameFilePredicate).findFirst();
+        if (conflictingFile.isPresent()) {
+            int firstDiffIndex = indexOfDifference(name, conflictingFile.get().getName());
+            StringBuilder newName = new StringBuilder(name.substring(0, firstDiffIndex));
+            PlatformNameFormat.addEscapedCharacter(newName, name.charAt(firstDiffIndex));
+            newName.append(name.substring(firstDiffIndex+1));
+            return newName.toString();
+        } else {
+            return name;
+        }
+    }
+
+    /**
+     * Compares two Strings, and returns the index at which the
+     * Strings begin to differ.
+     *
+     * For example,
+     * <code>indexOfDifference("i am a machine", "i am a robot") -> 7</code>
+     *
+     * <pre>
+     * StringUtils.indexOfDifference(null, null) = -1
+     * StringUtils.indexOfDifference("", "") = -1
+     * StringUtils.indexOfDifference("", "abc") = 0
+     * StringUtils.indexOfDifference("abc", "") = 0
+     * StringUtils.indexOfDifference("abc", "abc") = -1
+     * StringUtils.indexOfDifference("ab", "abxyz") = 2
+     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
+     * StringUtils.indexOfDifference("abcde", "xyz") = 0
+     * </pre>
+     *
+     * @param str1  the first String, may be null
+     * @param str2  the second String, may be null
+     * @return the index where str2 and str1 begin to differ; -1 if they are equal
+     */
+    private static int indexOfDifference(String str1, String str2) {
+        if (str1 == str2) {
+            return -1;
+        }
+        if (str1 == null || str2 == null) {
+            return 0;
+        }
+        int i;
+        for (i = 0; i < str1.length() && i < str2.length(); ++i) {
+            if (str1.charAt(i) != str2.charAt(i)) {
+                break;
+            }
+        }
+        if (i < str2.length() || i < str1.length()) {
+            return i;
+        }
+        return -1;
+    }
+
     public VltDirectory getParent() throws VltException {
         return new VltDirectory(ctx, dir.getParentFile());
     }
diff --git a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
index d7c970e..68e07a0 100644
--- a/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
+++ b/vault-vlt/src/main/java/org/apache/jackrabbit/vault/vlt/VltFile.java
@@ -95,6 +95,10 @@
     public VltFile(VltDirectory parent, String name, VltEntry entry)
             throws VltException {
         this.parent = parent;
+        if (entry == null) {
+            // potentially modify the name
+            name = parent.escapeToMakeUnique(name);
+        }
         this.name = name;
         this.entry = entry;
         this.file = new File(parent.getDirectory(), name);