001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.vfs; 021 022 import org.crsh.util.BaseIterator; 023 024 import java.util.Iterator; 025 import java.util.NoSuchElementException; 026 027 public final class Path implements Iterable<String> { 028 029 /** . */ 030 private static final String[] EMPTY_STRING = new String[0]; 031 032 /** . */ 033 private final boolean dir; 034 035 /** . */ 036 private final String[] names; 037 038 /** . */ 039 private String value; 040 041 public static Path get(Path parent, String name, boolean dir) { 042 if (!parent.dir) { 043 throw new IllegalArgumentException("Not a dir"); 044 } 045 int length = parent.names.length; 046 String[] names = new String[length + 1]; 047 System.arraycopy(parent.names, 0, names, 0, length); 048 names[length] = name; 049 return new Path(dir, names); 050 } 051 052 public static Path get(String s) { 053 if (s.length() == 0) { 054 throw new IllegalArgumentException("No empty path"); 055 } 056 if (s.charAt(0) != '/') { 057 throw new IllegalArgumentException("Path " + s + " must begin with a '/'"); 058 } 059 060 // 061 int start = 0; 062 int end = s.length(); 063 String[] names = EMPTY_STRING; 064 while (start < end) { 065 if (s.charAt(end - 1) == '/') { 066 end--; 067 } else if (s.charAt(start) == '/') { 068 start++; 069 } else { 070 names = parseNames(s, start, end, 0); 071 break; 072 } 073 } 074 075 // 076 return new Path(end < s.length(), names); 077 } 078 079 private static String[] parseNames(final String s, final int prev, int end, final int count) { 080 int next = s.indexOf('/', prev); 081 if (next == -1 || next > end) { 082 if (prev < end) { 083 String[] ret = new String[count + 1]; 084 ret[count] = s.substring(prev); 085 return ret; 086 } else { 087 return new String[count]; 088 } 089 } else if (next - prev > 0) { 090 String[] ret = parseNames(s, next + 1, end, count + 1); 091 ret[count] = s.substring(prev, next); 092 return ret; 093 } else { 094 return parseNames(s, next + 1, end, count); 095 } 096 } 097 098 private Path(boolean dir, String[] names) { 099 this.dir = dir; 100 this.names = names; 101 } 102 103 public Iterator<String> iterator() { 104 return new BaseIterator<String>() { 105 int index = 0; 106 public boolean hasNext() { 107 return index < names.length; 108 } 109 public String next() { 110 if (index < names.length) { 111 return names[index++]; 112 } else { 113 throw new NoSuchElementException(); 114 } 115 } 116 }; 117 } 118 119 public int getSize() { 120 return names.length; 121 } 122 123 public boolean isDir() { 124 return dir; 125 } 126 127 public String getName() { 128 return names.length > 0 ? names[names.length - 1] : ""; 129 } 130 131 public boolean isChildOf(Path parent) { 132 if (parent.dir) { 133 int length = parent.names.length; 134 if (names.length == length + 1) { 135 for (int i = 0;i < length;i++) { 136 if (names[i].equals(parent.names[i])) { 137 return false; 138 } 139 } 140 return true; 141 } 142 } 143 return false; 144 } 145 146 @Override 147 public boolean equals(Object o) { 148 if (o == this) { 149 return true; 150 } 151 if (o instanceof Path) { 152 Path that = (Path)o; 153 int length = that.names.length; 154 if (names.length == length) { 155 for (int i = 0;i < length;i++) { 156 if (!names[i].equals(that.names[i])) { 157 return false; 158 } 159 } 160 return true; 161 } 162 } 163 return false; 164 } 165 166 @Override 167 public int hashCode() { 168 int hashCode = dir ? 1 : 0; 169 for (int i = names.length - 1;i >= 0;i--) { 170 hashCode = hashCode * 41 + names[i].hashCode(); 171 } 172 return hashCode; 173 } 174 175 /** 176 * Returns the canonical path value. 177 * 178 * @return the value 179 */ 180 public String getValue() { 181 if (value == null) { 182 StringBuilder sb = new StringBuilder(8 * names.length); 183 for (String name : names) { 184 sb.append('/').append(name); 185 } 186 if (dir) { 187 sb.append('/'); 188 } 189 value = sb.toString(); 190 } 191 return value; 192 } 193 194 public String toString() { 195 return "Path[value=" + getValue() + "]"; 196 } 197 }