String (@NotNull String basePath, @NotNull String filePath, char separator, boolean caseSensitive) { basePath = ensureEnds(basePath, separator); if (caseSensitive ? basePath.equals(ensureEnds(filePath, separator)) : basePath.equalsIgnoreCase(ensureEnds(filePath, separator))) { return "."; } int len = 0; int lastSeparatorIndex = 0; // need this for cases like this: base="/temp/abc/base" and file="/temp/ab" CharComparingStrategy strategy = caseSensitive ? CharComparingStrategy.IDENTITY : CharComparingStrategy.CASE_INSENSITIVE; while (len < filePath.length() && len < basePath.length() && strategy.charsEqual(filePath.charAt(len), basePath.charAt(len))) { if (basePath.charAt(len) == separator) { lastSeparatorIndex = len; } len++; } if (len == 0) return null; StringBuilder relativePath = new StringBuilder(); for (int i = len; i < basePath.length(); i++) { if (basePath.charAt(i) == separator) { relativePath.append(".."); relativePath.append(separator); } } relativePath.append(filePath.substring(lastSeparatorIndex + 1)); return relativePath.toString(); }