001/* 
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.webengine.jaxrs.servlet.mapping;
013
014/**
015 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
016 */
017public class PathParser {
018
019    protected String[] array;
020
021    protected int count;
022
023    protected char[] buf;
024
025    protected int bufCount;
026
027    public PathParser() {
028        reset();
029    }
030
031    public void reset() {
032        array = new String[16];
033        buf = new char[16];
034        count = 0;
035        bufCount = 0;
036    }
037
038    public Path parse(String path) {
039        return parse(path, -1);
040    }
041
042    public Path parse(String path, int userBits) {
043        char[] chars = path.toCharArray();
044        if (chars.length == 0) {
045            return Path.EMPTY;
046        }
047        if (chars.length == 1 && chars[0] == '/') {
048            return Path.ROOT;
049        }
050
051        int i = 0;
052        int len = chars.length;
053        int bits = 0;
054        if (chars[chars.length - 1] == '/') {
055            bits |= Path.HAS_TRAILING_SLASH;
056            len--;
057        }
058        if (chars[0] == '/') {
059            bits |= Path.HAS_LEADING_SLASH;
060            i++;
061        }
062
063        for (; i < len; i++) {
064            char c = chars[i];
065            if (c == '/') {
066                if (hasSegment()) {
067                    addSegment(currentSegment());
068                    resetBuf();
069                } // else -> duplicate / - it will be ignored
070            } else {
071                append(c);
072            }
073        }
074        if (hasSegment()) {
075            addSegment(currentSegment());
076        }
077
078        return new Path(getSegments(), userBits == -1 ? bits : userBits);
079    }
080
081    public void back() {
082        if (count == 0) {
083            add("..");
084        } else {
085            count--;
086        }
087    }
088
089    public void addSegment(String segment) {
090        if ("..".equals(segment)) {
091            back();
092        } else if (!".".equals(segment)) {
093            add(segment);
094        }
095    }
096
097    public String[] getSegments() {
098        String[] result = new String[count];
099        System.arraycopy(array, 0, result, 0, count);
100        return result;
101    }
102
103    private final void add(String segment) {
104        if (count + 1 == array.length) {
105            String[] result = new String[count + 16];
106            System.arraycopy(array, 0, result, 0, count);
107            array = result;
108        }
109        array[count++] = segment;
110    }
111
112    private final void append(char c) {
113        if (bufCount + 1 == buf.length) {
114            char[] result = new char[bufCount + 16];
115            System.arraycopy(buf, 0, result, 0, bufCount);
116            buf = result;
117        }
118        buf[bufCount++] = c;
119    }
120
121    private final String currentSegment() {
122        return new String(buf, 0, bufCount);
123    }
124
125    private final boolean hasSegment() {
126        return bufCount > 0;
127    }
128
129    private final void resetBuf() {
130        bufCount = 0;
131    }
132
133}