1 package ch
.cyberduck
.core
;
4 * Copyright (c) 2002-2013 David Kocher. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to feedback@cyberduck.ch
20 import ch
.cyberduck
.core
.preferences
.PreferencesFactory
;
21 import ch
.cyberduck
.core
.unicode
.NFCNormalizer
;
23 import org
.apache
.commons
.io
.FilenameUtils
;
24 import org
.apache
.commons
.lang3
.StringUtils
;
26 import java
.util
.List
;
31 public final class PathNormalizer
{
33 private PathNormalizer() {
37 public static String
name(final String path
) {
38 final String normalized
= normalize(path
, true);
39 if(String
.valueOf(Path
.DELIMITER
).equals(normalized
)) {
42 return FilenameUtils
.getName(normalized
);
45 public static String
parent(final String absolute
, final char delimiter
) {
46 if(absolute
.equals(String
.valueOf(delimiter
))) {
49 int index
= absolute
.length() - 1;
50 if(absolute
.charAt(index
) == delimiter
) {
55 int cut
= absolute
.lastIndexOf(delimiter
, index
);
57 return absolute
.substring(0, cut
);
59 //if (index == 0) parent is root
60 return String
.valueOf(delimiter
);
63 public static String
normalize(final String path
) {
64 return normalize(path
, true);
68 * Return a context-relative path, beginning with a "/", that represents
69 * the canonical version of the specified path after ".." and "." elements
72 * @param path The path to parse
73 * @param absolute If the path is absolute
74 * @return the normalized path.
76 public static String
normalize(final String path
, final boolean absolute
) {
78 return String
.valueOf(Path
.DELIMITER
);
80 String normalized
= path
;
81 if(PreferencesFactory
.get().getBoolean("path.normalize")) {
83 while(!normalized
.startsWith(String
.valueOf(Path
.DELIMITER
))) {
84 normalized
= Path
.DELIMITER
+ normalized
;
87 while(!normalized
.endsWith(String
.valueOf(Path
.DELIMITER
))) {
88 normalized
+= Path
.DELIMITER
;
90 // Resolve occurrences of "/./" in the normalized path
92 int index
= normalized
.indexOf("/./");
96 normalized
= normalized
.substring(0, index
) +
97 normalized
.substring(index
+ 2);
99 // Resolve occurrences of "/../" in the normalized path
101 int index
= normalized
.indexOf("/../");
106 // The only left path is the root.
107 return String
.valueOf(Path
.DELIMITER
);
109 normalized
= normalized
.substring(0, normalized
.lastIndexOf(Path
.DELIMITER
, index
- 1)) +
110 normalized
.substring(index
+ 3);
112 StringBuilder n
= new StringBuilder();
113 if(normalized
.startsWith("//")) {
114 // see #972. Omit leading delimiter
115 n
.append(Path
.DELIMITER
);
116 n
.append(Path
.DELIMITER
);
119 // convert to absolute path
120 n
.append(Path
.DELIMITER
);
122 else if(normalized
.startsWith(String
.valueOf(Path
.DELIMITER
))) {
123 // Keep absolute path
124 n
.append(Path
.DELIMITER
);
126 // Remove duplicated Path.DELIMITERs
127 final String
[] segments
= normalized
.split(String
.valueOf(Path
.DELIMITER
));
128 for(String segment
: segments
) {
129 if(segment
.equals(StringUtils
.EMPTY
)) {
133 n
.append(Path
.DELIMITER
);
135 normalized
= n
.toString();
136 while(normalized
.endsWith(String
.valueOf(Path
.DELIMITER
)) && normalized
.length() > 1) {
137 //Strip any redundant delimiter at the end of the path
138 normalized
= normalized
.substring(0, normalized
.length() - 1);
141 if(PreferencesFactory
.get().getBoolean("path.normalize.unicode")) {
142 return new NFCNormalizer().normalize(normalized
);
144 // Return the normalized path that we have completed
149 * Prunes the list of selected files. Files which are a child of an already included directory
150 * are removed from the returned list.
152 * @param selected Selected files for transfer
155 public static List
<Path
> normalize(final List
<Path
> selected
) {
156 final List
<Path
> normalized
= new Collection
<Path
>();
157 for(Path f
: selected
) {
158 boolean duplicate
= false;
159 for(Path n
: normalized
) {
161 // The selected file is a child of a directory already included