Home | History | Annotate | Download | only in data
      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     MediaObject getObject() {
     76         synchronized (Path.class) {
     77             return (mObject == null) ? null : mObject.get();
     78         }
     79     }
     80 
     81     @Override
     82     // TODO: toString() should be more efficient, will fix it later
     83     public String toString() {
     84         synchronized (Path.class) {
     85             StringBuilder sb = new StringBuilder();
     86             String[] segments = split();
     87             for (int i = 0; i < segments.length; i++) {
     88                 sb.append("/");
     89                 sb.append(segments[i]);
     90             }
     91             return sb.toString();
     92         }
     93     }
     94 
     95     public boolean equalsIgnoreCase (String p) {
     96         String path = toString();
     97         return path.equalsIgnoreCase(p);
     98     }
     99 
    100     public static Path fromString(String s) {
    101         synchronized (Path.class) {
    102             String[] segments = split(s);
    103             Path current = sRoot;
    104             for (int i = 0; i < segments.length; i++) {
    105                 current = current.getChild(segments[i]);
    106             }
    107             return current;
    108         }
    109     }
    110 
    111     public String[] split() {
    112         synchronized (Path.class) {
    113             int n = 0;
    114             for (Path p = this; p != sRoot; p = p.mParent) {
    115                 n++;
    116             }
    117             String[] segments = new String[n];
    118             int i = n - 1;
    119             for (Path p = this; p != sRoot; p = p.mParent) {
    120                 segments[i--] = p.mSegment;
    121             }
    122             return segments;
    123         }
    124     }
    125 
    126     public static String[] split(String s) {
    127         int n = s.length();
    128         if (n == 0) return new String[0];
    129         if (s.charAt(0) != '/') {
    130             throw new RuntimeException("malformed path:" + s);
    131         }
    132         ArrayList<String> segments = new ArrayList<String>();
    133         int i = 1;
    134         while (i < n) {
    135             int brace = 0;
    136             int j;
    137             for (j = i; j < n; j++) {
    138                 char c = s.charAt(j);
    139                 if (c == '{') ++brace;
    140                 else if (c == '}') --brace;
    141                 else if (brace == 0 && c == '/') break;
    142             }
    143             if (brace != 0) {
    144                 throw new RuntimeException("unbalanced brace in path:" + s);
    145             }
    146             segments.add(s.substring(i, j));
    147             i = j + 1;
    148         }
    149         String[] result = new String[segments.size()];
    150         segments.toArray(result);
    151         return result;
    152     }
    153 
    154     // Splits a string to an array of strings.
    155     // For example, "{foo,bar,baz}" -> {"foo","bar","baz"}.
    156     public static String[] splitSequence(String s) {
    157         int n = s.length();
    158         if (s.charAt(0) != '{' || s.charAt(n-1) != '}') {
    159             throw new RuntimeException("bad sequence: " + s);
    160         }
    161         ArrayList<String> segments = new ArrayList<String>();
    162         int i = 1;
    163         while (i < n - 1) {
    164             int brace = 0;
    165             int j;
    166             for (j = i; j < n - 1; j++) {
    167                 char c = s.charAt(j);
    168                 if (c == '{') ++brace;
    169                 else if (c == '}') --brace;
    170                 else if (brace == 0 && c == ',') break;
    171             }
    172             if (brace != 0) {
    173                 throw new RuntimeException("unbalanced brace in path:" + s);
    174             }
    175             segments.add(s.substring(i, j));
    176             i = j + 1;
    177         }
    178         String[] result = new String[segments.size()];
    179         segments.toArray(result);
    180         return result;
    181     }
    182 
    183     public String getPrefix() {
    184         if (this == sRoot) return "";
    185         return getPrefixPath().mSegment;
    186     }
    187 
    188     public Path getPrefixPath() {
    189         synchronized (Path.class) {
    190             Path current = this;
    191             if (current == sRoot) {
    192                 throw new IllegalStateException();
    193             }
    194             while (current.mParent != sRoot) {
    195                 current = current.mParent;
    196             }
    197             return current;
    198         }
    199     }
    200 
    201     public String getSuffix() {
    202         // We don't need lock because mSegment is final.
    203         return mSegment;
    204     }
    205 
    206     // Below are for testing/debugging only
    207     static void clearAll() {
    208         synchronized (Path.class) {
    209             sRoot = new Path(null, "");
    210         }
    211     }
    212 
    213     static void dumpAll() {
    214         dumpAll(sRoot, "", "");
    215     }
    216 
    217     static void dumpAll(Path p, String prefix1, String prefix2) {
    218         synchronized (Path.class) {
    219             MediaObject obj = p.getObject();
    220             Log.d(TAG, prefix1 + p.mSegment + ":"
    221                     + (obj == null ? "null" : obj.getClass().getSimpleName()));
    222             if (p.mChildren != null) {
    223                 ArrayList<String> childrenKeys = p.mChildren.keys();
    224                 int i = 0, n = childrenKeys.size();
    225                 for (String key : childrenKeys) {
    226                     Path child = p.mChildren.get(key);
    227                     if (child == null) {
    228                         ++i;
    229                         continue;
    230                     }
    231                     Log.d(TAG, prefix2 + "|");
    232                     if (++i < n) {
    233                         dumpAll(child, prefix2 + "+-- ", prefix2 + "|   ");
    234                     } else {
    235                         dumpAll(child, prefix2 + "+-- ", prefix2 + "    ");
    236                     }
    237                 }
    238             }
    239         }
    240     }
    241 }
    242