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     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