blob: 40fd3981c2b9826f3e27075e7a1aa53c2f51cdd8 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.jimfs;
import com.google.common.base.Ascii;
import com.google.common.base.Function;
import com.ibm.icu.lang.UCharacter;
import java.text.Normalizer;
import java.util.regex.Pattern;
/**
* Normalizations that can be applied to names in paths. Includes Unicode normalizations and
* normalizations for case insensitive paths. These normalizations can be set in {@code
* Configuration.Builder} when creating a Jimfs file system instance and are automatically applied
* to paths in the file system.
*
* @author Colin Decker
*/
public enum PathNormalization implements Function<String, String> {
/** No normalization. */
NONE(0) {
@Override
public String apply(String string) {
return string;
}
},
/** Unicode composed normalization (form {@linkplain java.text.Normalizer.Form#NFC NFC}). */
NFC(Pattern.CANON_EQ) {
@Override
public String apply(String string) {
return Normalizer.normalize(string, Normalizer.Form.NFC);
}
},
/** Unicode decomposed normalization (form {@linkplain java.text.Normalizer.Form#NFD NFD}). */
NFD(Pattern.CANON_EQ) {
@Override
public String apply(String string) {
return Normalizer.normalize(string, Normalizer.Form.NFD);
}
},
/*
* Some notes on case folding/case insensitivity of file systems:
*
* In general (I don't have any counterexamples) case-insensitive file systems handle
* their case insensitivity in a locale-independent way. NTFS, for example, writes a
* special case mapping file ($UpCase) to the file system when it's first initialized,
* and this is not affected by the locale of either the user or the copy of Windows
* being used. This means that it will NOT handle i/I-variants in filenames as you'd
* expect for Turkic languages, even for a Turkish user who has installed a Turkish
* copy of Windows.
*/
/** Unicode case folding for case insensitive paths. Requires ICU4J on the classpath. */
CASE_FOLD_UNICODE(Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) {
@Override
public String apply(String string) {
try {
return UCharacter.foldCase(string, true);
} catch (NoClassDefFoundError e) {
NoClassDefFoundError error =
new NoClassDefFoundError(
"PathNormalization.CASE_FOLD_UNICODE requires ICU4J. "
+ "Did you forget to include it on your classpath?");
error.initCause(e);
throw error;
}
}
},
/** ASCII case folding for simple case insensitive paths. */
CASE_FOLD_ASCII(Pattern.CASE_INSENSITIVE) {
@Override
public String apply(String string) {
return Ascii.toLowerCase(string);
}
};
private final int patternFlags;
private PathNormalization(int patternFlags) {
this.patternFlags = patternFlags;
}
/** Applies this normalization to the given string, returning the normalized result. */
@Override
public abstract String apply(String string);
/**
* Returns the flags that should be used when creating a regex {@link Pattern} in order to
* approximate this normalization.
*/
public int patternFlags() {
return patternFlags;
}
/**
* Applies the given normalizations to the given string in order, returning the normalized result.
*/
public static String normalize(String string, Iterable<PathNormalization> normalizations) {
String result = string;
for (PathNormalization normalization : normalizations) {
result = normalization.apply(result);
}
return result;
}
/** Compiles a regex pattern using flags based on the given normalizations. */
public static Pattern compilePattern(String regex, Iterable<PathNormalization> normalizations) {
int flags = 0;
for (PathNormalization normalization : normalizations) {
flags |= normalization.patternFlags();
}
return Pattern.compile(regex, flags);
}
}