com.github.sommeri.less4j.utils.RelativeFilenameUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of less4j Show documentation
Show all versions of less4j Show documentation
Less language is an extension of css and less4j compiles it into regular css. It adds several dynamic features into css: variables, expressions, nested rules.
Less4j is a port. The original compiler was written in JavaScript and is called less.js. The less language is mostly defined in less.js documentation/issues and by what less.js actually do. Links to less.js:
* home page: http://lesscss.org/
* source code & issues: https://github.com/cloudhead/less.js
package com.github.sommeri.less4j.utils;
import java.io.File;
import org.apache.commons.io.FilenameUtils;
//copied from org.apache.commons.io.FilenameUtils.doNormalize and customized
public class RelativeFilenameUtils {
private static final char SYSTEM_SEPARATOR = File.separatorChar;
private static final char UNIX_SEPARATOR = '/';
private static final char WINDOWS_SEPARATOR = '\\';
private static final char OTHER_SEPARATOR;
static {
if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
OTHER_SEPARATOR = UNIX_SEPARATOR;
} else {
OTHER_SEPARATOR = WINDOWS_SEPARATOR;
}
}
public static String normalizeNoEndSeparator(String filename) {
return doNormalize(filename, SYSTEM_SEPARATOR, false);
}
private static String doNormalize(String filename, char separator, boolean keepSeparator) {
if (filename == null) {
return null;
}
int size = filename.length();
if (size == 0) {
return filename;
}
int prefix = FilenameUtils.getPrefixLength(filename);
if (prefix < 0) {
return null;
}
char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy
filename.getChars(0, filename.length(), array, 0);
// fix separators throughout
char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR;
for (int i = 0; i < array.length; i++) {
if (array[i] == otherSeparator) {
array[i] = separator;
}
}
// add extra separator on the end to simplify code below
boolean lastIsDirectory = true;
if (array[size - 1] != separator) {
array[size++] = separator;
lastIsDirectory = false;
}
// adjoining slashes
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == separator) {
System.arraycopy(array, i, array, i - 1, size - i);
size--;
i--;
}
}
// dot slash
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == '.' && (i == prefix + 1 || array[i - 2] == separator)) {
if (i == size - 1) {
lastIsDirectory = true;
}
System.arraycopy(array, i + 1, array, i - 1, size - i);
size -= 2;
i--;
}
}
// double dot slash
outer: for (int i = prefix + 2; i < size; i++) {
if (isEndOfClimbUp(array, i, separator) && (i == prefix + 2 || array[i - 3] == separator)) {
//if (located in the beginning or after drive or server name)
if (i == prefix + 2) {
// Modified by SomMeri to allow relative paths
//return null;
continue outer;
}
if (i == size - 1) {
lastIsDirectory = true;
}
if (isEndOfClimbUp(array, i - 3, separator)) {
// We reached previous climb up. That can happen only if we are at the
// beginning of the path and the path is starting with some climbs. e.g.
// path looks somewhat like this: ../../something
//
// We cannot climb further, so no action is needed.
} else {
int j;
for (j = i - 4; j >= prefix; j--) {
if (array[j] == separator) {
// remove b/../ from a/b/../c
System.arraycopy(array, i + 1, array, j + 1, size - i);
size -= i - j;
i = j + 1;
continue outer;
}
}
// remove a/../ from a/../c
System.arraycopy(array, i + 1, array, prefix, size - i);
size -= i + 1 - prefix;
i = prefix + 1;
}
}
}
if (size <= 0) { // should never be less than 0
return "";
}
if (size <= prefix) { // should never be less than prefix
return new String(array, 0, size);
}
if (lastIsDirectory && keepSeparator) {
return new String(array, 0, size); // keep trailing separator
}
return new String(array, 0, size - 1); // lose trailing separator
}
private static boolean isEndOfClimbUp(char[] array, int position, char separator) {
return array[position] == separator && array[position - 1] == '.' && array[position - 2] == '.';
}
}