1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.data; 18 19 import com.android.gallery3d.common.Utils; 20 import com.android.gallery3d.util.IdentityCache; 21 22 import java.lang.ref.WeakReference; 23 import java.util.ArrayList; 24 25 public class Path { 26 private static final String TAG = "Path"; 27 private static Path sRoot = new Path(null, "ROOT"); 28 29 private final Path mParent; 30 private final String mSegment; 31 private WeakReference<MediaObject> mObject; 32 private IdentityCache<String, Path> mChildren; 33 34 private Path(Path parent, String segment) { 35 mParent = parent; 36 mSegment = segment; 37 } 38 39 public Path getChild(String segment) { 40 synchronized (Path.class) { 41 if (mChildren == null) { 42 mChildren = new IdentityCache<String, Path>(); 43 } else { 44 Path p = mChildren.get(segment); 45 if (p != null) return p; 46 } 47 48 Path p = new Path(this, segment); 49 mChildren.put(segment, p); 50 return p; 51 } 52 } 53 54 public Path getParent() { 55 synchronized (Path.class) { 56 return mParent; 57 } 58 } 59 60 public Path getChild(int segment) { 61 return getChild(String.valueOf(segment)); 62 } 63 64 public Path getChild(long segment) { 65 return getChild(String.valueOf(segment)); 66 } 67 68 public void setObject(MediaObject object) { 69 synchronized (Path.class) { 70 Utils.assertTrue(mObject == null || mObject.get() == null); 71 mObject = new WeakReference<MediaObject>(object); 72 } 73 } 74 75 public MediaObject getObject() { 76 synchronized (Path.class) { 77 return (mObject == null) ? null : mObject.get(); 78 } 79 } 80 81 @Override 82 public String toString() { 83 synchronized (Path.class) { 84 StringBuilder sb = new StringBuilder(); 85 String[] segments = split(); 86 for (int i = 0; i < segments.length; i++) { 87 sb.append("/"); 88 sb.append(segments[i]); 89 } 90 return sb.toString(); 91 } 92 } 93 94 public static Path fromString(String s) { 95 synchronized (Path.class) { 96 String[] segments = split(s); 97 Path current = sRoot; 98 for (int i = 0; i < segments.length; i++) { 99 current = current.getChild(segments[i]); 100 } 101 return current; 102 } 103 } 104 105 public String[] split() { 106 synchronized (Path.class) { 107 int n = 0; 108 for (Path p = this; p != sRoot; p = p.mParent) { 109 n++; 110 } 111 String[] segments = new String[n]; 112 int i = n - 1; 113 for (Path p = this; p != sRoot; p = p.mParent) { 114 segments[i--] = p.mSegment; 115 } 116 return segments; 117 } 118 } 119 120 public static String[] split(String s) { 121 int n = s.length(); 122 if (n == 0) return new String[0]; 123 if (s.charAt(0) != '/') { 124 throw new RuntimeException("malformed path:" + s); 125 } 126 ArrayList<String> segments = new ArrayList<String>(); 127 int i = 1; 128 while (i < n) { 129 int brace = 0; 130 int j; 131 for (j = i; j < n; j++) { 132 char c = s.charAt(j); 133 if (c == '{') ++brace; 134 else if (c == '}') --brace; 135 else if (brace == 0 && c == '/') break; 136 } 137 if (brace != 0) { 138 throw new RuntimeException("unbalanced brace in path:" + s); 139 } 140 segments.add(s.substring(i, j)); 141 i = j + 1; 142 } 143 String[] result = new String[segments.size()]; 144 segments.toArray(result); 145 return result; 146 } 147 148 // Splits a string to an array of strings. 149 // For example, "{foo,bar,baz}" -> {"foo","bar","baz"}. 150 public static String[] splitSequence(String s) { 151 int n = s.length(); 152 if (s.charAt(0) != '{' || s.charAt(n-1) != '}') { 153 throw new RuntimeException("bad sequence: " + s); 154 } 155 ArrayList<String> segments = new ArrayList<String>(); 156 int i = 1; 157 while (i < n - 1) { 158 int brace = 0; 159 int j; 160 for (j = i; j < n - 1; j++) { 161 char c = s.charAt(j); 162 if (c == '{') ++brace; 163 else if (c == '}') --brace; 164 else if (brace == 0 && c == ',') break; 165 } 166 if (brace != 0) { 167 throw new RuntimeException("unbalanced brace in path:" + s); 168 } 169 segments.add(s.substring(i, j)); 170 i = j + 1; 171 } 172 String[] result = new String[segments.size()]; 173 segments.toArray(result); 174 return result; 175 } 176 177 public String getPrefix() { 178 synchronized (Path.class) { 179 Path current = this; 180 if (current == sRoot) return ""; 181 while (current.mParent != sRoot) { 182 current = current.mParent; 183 } 184 return current.mSegment; 185 } 186 } 187 188 public String getSuffix() { 189 // We don't need lock because mSegment is final. 190 return mSegment; 191 } 192 193 public String getSuffix(int level) { 194 // We don't need lock because mSegment and mParent are final. 195 Path p = this; 196 while (level-- != 0) { 197 p = p.mParent; 198 } 199 return p.mSegment; 200 } 201 202 // Below are for testing/debugging only 203 static void clearAll() { 204 synchronized (Path.class) { 205 sRoot = new Path(null, ""); 206 } 207 } 208 209 static void dumpAll() { 210 dumpAll(sRoot, "", ""); 211 } 212 213 static void dumpAll(Path p, String prefix1, String prefix2) { 214 synchronized (Path.class) { 215 MediaObject obj = p.getObject(); 216 Log.d(TAG, prefix1 + p.mSegment + ":" 217 + (obj == null ? "null" : obj.getClass().getSimpleName())); 218 if (p.mChildren != null) { 219 ArrayList<String> childrenKeys = p.mChildren.keys(); 220 int i = 0, n = childrenKeys.size(); 221 for (String key : childrenKeys) { 222 Path child = p.mChildren.get(key); 223 if (child == null) { 224 ++i; 225 continue; 226 } 227 Log.d(TAG, prefix2 + "|"); 228 if (++i < n) { 229 dumpAll(child, prefix2 + "+-- ", prefix2 + "| "); 230 } else { 231 dumpAll(child, prefix2 + "+-- ", prefix2 + " "); 232 } 233 } 234 } 235 } 236 } 237 } 238