/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.wc;
import java.io.File;
import java.util.Map;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class SVNFileListUtil {
private static boolean ourIsCompositionEnabled = Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("svnkit.fs.composeFileNames", "true"));
public static synchronized void setCompositionEnabled(boolean enabled) {
ourIsCompositionEnabled = enabled;
}
public static synchronized boolean isCompositionEnabled() {
return ourIsCompositionEnabled;
}
/**
* This method is a replacement for file.list(), which composes decomposed file names (e.g. umlauts in file names on the Mac).
*/
private static String[] list(File directory) {
if (!SVNFileUtil.isOSX) {
return directory.list();
}
final String[] fileNames = directory.list();
if (fileNames == null) {
return null;
}
final String[] composedFileNames = new String[fileNames.length];
for (int i = 0; i < composedFileNames.length; i++) {
if (!isCompositionEnabled()) {
composedFileNames[i] = decompose(fileNames[i]);
} else {
composedFileNames[i] = compose(fileNames[i]);
}
}
return composedFileNames;
}
/**
* This method is a replacement for file.listFiles(), which composes decomposed file names (e.g. umlauts in file names on the Mac).
*/
public static File[] listFiles(File directory) {
if (SVNFileUtil.isOSX) {
final String[] fileNames = list(directory);
if (fileNames == null) {
return null;
}
File[] files = new File[fileNames.length];
for (int i = 0; i < files.length; i++) {
files[i] = new File(directory.getPath(), fileNames[i]);
}
return files;
} else if (SVNFileUtil.isOpenVMS) {
File[] files = directory.listFiles();
if (files == null || files.length == 0) {
return files;
}
File[] processed = new File[files.length];
for (int i = 0; i < files.length; i++) {
File file = files[i];
String name = file.getName();
if (file.isFile() && name.endsWith(".")) {
// chances there is a file without extension and '.' added by openVMS.
name = name.substring(0, name.lastIndexOf('.'));
file = new File(directory, name);
if (file.exists() && file.isFile()) {
processed[i] = file;
continue;
}
}
processed[i] = file;
}
return processed;
}
final File[] files = directory.listFiles();
return files != null ? sort(files) : null;
}
private static File[] sort(File[] files) {
final Map<String,File> map = new SVNHashMap();
for (int i = 0; i < files.length; i++) {
map.put(files[i].getName(), files[i]);
}
return map.values().toArray(new File[map.size()]);
}
private static String compose(String decomposedString) {
if (decomposedString == null) {
return null;
}
StringBuffer buffer = null;
for (int i = 1, length = decomposedString.length(); i < length; i++) {
final char chr = decomposedString.charAt(i);
if (chr == '\u0300') { // grave `
buffer = compose(i, "AaEeIiOoUu", "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9", decomposedString, buffer);
}
else if (chr == '\u0301') { // acute '
buffer = compose(i, "AaEeIiOoUuYy", "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD", decomposedString, buffer);
}
else if (chr == '\u0302') { // circumflex ^
buffer = compose(i, "AaEeIiOoUuYy", "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177", decomposedString, buffer);
}
else if (chr == '\u0303') { // tilde ~
buffer = compose(i, "AaNnOoUu", "\u00C3\u00E3\u00D1\u00F1\u00D5\u00F5\u0168\u0169", decomposedString, buffer);
}
else if (chr == '\u0308') { // umlaut/dieresis (two dots above)
buffer = compose(i, "AaEeIiOoUuYy", "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF", decomposedString, buffer);
}
else if (chr == '\u030A') { // ring above (as in Angstrom)
buffer = compose(i, "Aa", "\u00C5\u00E5", decomposedString, buffer);
}
else if (chr == '\u0327') { // cedilla ,
buffer = compose(i, "Cc", "\u00C7\u00E7", decomposedString, buffer);
}
else if (buffer != null) {
buffer.append(chr);
}
}
if (buffer == null) {
return decomposedString;
}
return buffer.toString();
}
private static String decompose(String composedString) {
if (composedString == null) {
return null;
}
StringBuffer buffer = null;
for (int i = 0, length = composedString.length(); i < length; i++) {
final char chr = composedString.charAt(i);
switch (chr) {
case '\u00C0': buffer = decompose("A\u0300", i, composedString, buffer); break;
case '\u00C1': buffer = decompose("A\u0301", i, composedString, buffer); break;
case '\u00C2': buffer = decompose("A\u0302", i, composedString, buffer); break;
case '\u00C3': buffer = decompose("A\u0303", i, composedString, buffer); break;
case '\u00C4': buffer = decompose("A\u0308", i, composedString, buffer); break;
case '\u00C5': buffer = decompose("A\u030A", i, composedString, buffer); break;
case '\u00C7': buffer = decompose("C\u0327", i, composedString, buffer); break;
case '\u00C8': buffer = decompose("E\u0300", i, composedString, buffer); break;
case '\u00C9': buffer = decompose("E\u0301", i, composedString, buffer); break;
case '\u00CA': buffer = decompose("E\u0302", i, composedString, buffer); break;
case '\u00CB': buffer = decompose("E\u0308", i, composedString, buffer); break;
case '\u00CC': buffer = decompose("I\u0300", i, composedString, buffer); break;
case '\u00CD': buffer = decompose("I\u0301", i, composedString, buffer); break;
case '\u00CE': buffer = decompose("I\u0302", i, composedString, buffer); break;
case '\u00CF': buffer = decompose("I\u0308", i, composedString, buffer); break;
case '\u00D1': buffer = decompose("N\u0303", i, composedString, buffer); break;
case '\u00D2': buffer = decompose("O\u0300", i, composedString, buffer); break;
case '\u00D3': buffer = decompose("O\u0301", i, composedString, buffer); break;
case '\u00D4': buffer = decompose("O\u0302", i, composedString, buffer); break;
case '\u00D5': buffer = decompose("O\u0303", i, composedString, buffer); break;
case '\u00D6': buffer = decompose("O\u0308", i, composedString, buffer); break;
case '\u00D9': buffer = decompose("U\u0300", i, composedString, buffer); break;
case '\u00DA': buffer = decompose("U\u0301", i, composedString, buffer); break;
case '\u00DB': buffer = decompose("U\u0302", i, composedString, buffer); break;
case '\u00DC': buffer = decompose("U\u0308", i, composedString, buffer); break;
case '\u00DD': buffer = decompose("Y\u0301", i, composedString, buffer); break;
case '\u00E0': buffer = decompose("a\u0300", i, composedString, buffer); break;
case '\u00E1': buffer = decompose("a\u0301", i, composedString, buffer); break;
case '\u00E2': buffer = decompose("a\u0302", i, composedString, buffer); break;
case '\u00E3': buffer = decompose("a\u0303", i, composedString, buffer); break;
case '\u00E4': buffer = decompose("a\u0308", i, composedString, buffer); break;
case '\u00E5': buffer = decompose("a\u030A", i, composedString, buffer); break;
case '\u00E7': buffer = decompose("c\u0327", i, composedString, buffer); break;
case '\u00E8': buffer = decompose("e\u0300", i, composedString, buffer); break;
case '\u00E9': buffer = decompose("e\u0301", i, composedString, buffer); break;
case '\u00EA': buffer = decompose("e\u0302", i, composedString, buffer); break;
case '\u00EB': buffer = decompose("e\u0308", i, composedString, buffer); break;
case '\u00EC': buffer = decompose("i\u0300", i, composedString, buffer); break;
case '\u00ED': buffer = decompose("i\u0301", i, composedString, buffer); break;
case '\u00EE': buffer = decompose("i\u0302", i, composedString, buffer); break;
case '\u00EF': buffer = decompose("i\u0308", i, composedString, buffer); break;
case '\u00FF': buffer = decompose("y\u0308", i, composedString, buffer); break;
case '\u00F1': buffer = decompose("n\u0303", i, composedString, buffer); break;
case '\u00F2': buffer = decompose("o\u0300", i, composedString, buffer); break;
case '\u00F3': buffer = decompose("o\u0301", i, composedString, buffer); break;
case '\u00F4': buffer = decompose("o\u0302", i, composedString, buffer); break;
case '\u00F5': buffer = decompose("o\u0303", i, composedString, buffer); break;
case '\u00F6': buffer = decompose("o\u0308", i, composedString, buffer); break;
case '\u00F9': buffer = decompose("u\u0300", i, composedString, buffer); break;
case '\u00FA': buffer = decompose("u\u0301", i, composedString, buffer); break;
case '\u00FB': buffer = decompose("u\u0302", i, composedString, buffer); break;
case '\u00FC': buffer = decompose("u\u0308", i, composedString, buffer); break;
case '\u00FD': buffer = decompose("y\u0301", i, composedString, buffer); break;
case '\u0168': buffer = decompose("U\u0303", i, composedString, buffer); break;
case '\u0169': buffer = decompose("u\u0303", i, composedString, buffer); break;
case '\u0176': buffer = decompose("Y\u0302", i, composedString, buffer); break;
case '\u0177': buffer = decompose("y\u0302", i, composedString, buffer); break;
case '\u0178': buffer = decompose("Y\u0308", i, composedString, buffer); break;
default:
if (buffer != null) {
buffer.append(chr);
}
break;
}
}
if (buffer == null) {
return composedString;
}
return buffer.toString();
}
// Utils ==================================================================
private static StringBuffer decompose(String replacement, int index, String composedString, StringBuffer buffer) {
if (buffer == null) {
buffer = new StringBuffer(composedString.length());
buffer.append(composedString, 0, index);
}
buffer.append(replacement);
return buffer;
}
private static StringBuffer compose(int i, String decomposedChars, String composedChars, String decomposedString, StringBuffer buffer) {
final char previousChar = decomposedString.charAt(i - 1);
final int decomposedIndex = decomposedChars.indexOf(previousChar);
if (decomposedIndex >= 0) {
if (buffer == null) {
buffer = new StringBuffer(decomposedString.length() + 2);
buffer.append(decomposedString.substring(0, i - 1));
}
else {
buffer.delete(buffer.length() - 1, buffer.length());
}
buffer.append(composedChars.charAt(decomposedIndex));
}
else {
if (buffer == null) {
buffer = new StringBuffer(decomposedString.length() + 2);
buffer.append(decomposedString.substring(0, i));
}
}
return buffer;
}
}