You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2013/08/10 07:53:54 UTC

svn commit: r1512568 [22/39] - in /jackrabbit/commons/filevault/trunk: ./ parent/ vault-cli/ vault-cli/src/ vault-cli/src/main/ vault-cli/src/main/appassembler/ vault-cli/src/main/assembly/ vault-cli/src/main/java/ vault-cli/src/main/java/org/ vault-cl...

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.apache.jackrabbit.util.XMLChar;
+import org.apache.jackrabbit.value.ValueHelper;
+
+/**
+ * Helper class that represents a (jcr) property in the document view format.
+ * It contains formatting and parsing methods for writing/reading enhanced
+ * docview properties.
+ *
+ * <code>prop:= [ "{" type "}" ] ( value | "[" [ value { "," value } ] "]" )</code>
+ */
+public class DocViewProperty {
+
+    /**
+     * name of the property
+     */
+    public final String name;
+
+    /**
+     * value(s) of the property. always contains at least one value if this is
+     * not a mv property.
+     */
+    public final String[] values;
+
+    /**
+     * indicates a MV property
+     */
+    public final boolean isMulti;
+
+    /**
+     * type of this property (can be undefined)
+     */
+    public final int type;
+
+    /**
+     * set of unambigous property names
+     */
+    private static final Set<String> UNAMBIGOUS = new HashSet<String>();
+    static {
+        UNAMBIGOUS.add("jcr:primaryType");
+        UNAMBIGOUS.add("jcr:mixinTypes");
+    }
+
+    /**
+     * Creates a new property.
+     * @param name name of the property
+     * @param values values.
+     * @param multi multiple flag
+     * @param type type of the property
+     * @throws IllegalArgumentException if single value property and not
+     *         exactly 1 value is given.
+     */
+    public DocViewProperty(String name, String[] values, boolean multi, int type) {
+        this.name = name;
+        this.values = values;
+        isMulti = multi;
+        // validate type
+        if (type == PropertyType.UNDEFINED) {
+            if (name.equals("jcr:primaryType") || name.equals("jcr:mixinTypes")) {
+                type = PropertyType.NAME;
+            }
+        }
+        this.type = type;
+        if (!isMulti && values.length != 1) {
+            throw new IllegalArgumentException("Single value property needs exactly 1 value.");
+        }
+    }
+
+    /**
+     * Parses a enhanced docview property string and returns the property.
+     * @param name name of the property
+     * @param value (attribute) value
+     * @return a property
+     */
+    public static DocViewProperty parse(String name, String value) {
+        boolean isMulti = false;
+        int type = PropertyType.UNDEFINED;
+        int pos = 0;
+        char state = 'b';
+        List<String> vals = null;
+        StringBuffer tmp = new StringBuffer();
+        int unicode = 0;
+        int unicodePos = 0;
+        while (pos < value.length()) {
+            char c = value.charAt(pos++);
+            switch (state) {
+                case 'b': // begin (type or array or value)
+                    if (c == '{') {
+                        state = 't';
+                    } else if (c == '[') {
+                        isMulti = true;
+                        state = 'v';
+                    } else if (c == '\\') {
+                        state = 'e';
+                    } else {
+                        tmp.append(c);
+                        state = 'v';
+                    }
+                    break;
+                case 'a': // array (array or value)
+                    if (c == '[') {
+                        isMulti = true;
+                        state = 'v';
+                    } else if (c == '\\') {
+                        state = 'e';
+                    } else {
+                        tmp.append(c);
+                        state = 'v';
+                    }
+                    break;
+                case 't':
+                    if (c == '}') {
+                        type = PropertyType.valueFromName(tmp.toString());
+                        tmp.setLength(0);
+                        state = 'a';
+                    } else {
+                        tmp.append(c);
+                    }
+                    break;
+                case 'v': // value
+                    if (c == '\\') {
+                        state = 'e';
+                    } else if (c == ',' && isMulti) {
+                        if (vals == null) {
+                            vals = new LinkedList<String>();
+                        }
+                        vals.add(tmp.toString());
+                        tmp.setLength(0);
+                    } else if (c == ']' && isMulti && pos == value.length()) {
+                        if (tmp.length() > 0 || vals != null) {
+                            if (vals == null) {
+                                vals = new LinkedList<String>();
+                            }
+                            vals.add(tmp.toString());
+                            tmp.setLength(0);
+                        }
+                    } else {
+                        tmp.append(c);
+                    }
+                    break;
+                case 'e': // escaped
+                    if (c == 'u') {
+                        state = 'u';
+                        unicode = 0;
+                        unicodePos = 0;
+                    } else {
+                        state = 'v';
+                        tmp.append(c);
+                    }
+                    break;
+                case 'u': // unicode escaped
+                    unicode = (unicode << 4) + Character.digit(c, 16);
+                    if (++unicodePos == 4) {
+                        tmp.appendCodePoint(unicode);
+                        state = 'v';
+                    }
+                    break;
+
+            }
+        }
+        String[] values;
+        if (isMulti) {
+            // add value if missing ']'
+            if (tmp.length() > 0) {
+                if (vals == null) {
+                    vals = new LinkedList<String>();
+                }
+                vals.add(tmp.toString());
+            }
+            if (vals == null) {
+                values = Constants.EMPTY_STRING_ARRAY;
+            } else {
+                values = vals.toArray(new String[vals.size()]);
+            }
+        } else {
+            values = new String[]{tmp.toString()};
+        }
+        return new DocViewProperty(name, values, isMulti, type);
+    }
+    /**
+     * Formats the given jcr property to the enhanced docview syntax.
+     * @param prop the jcr property
+     * @return the formatted string
+     * @throws RepositoryException if a repository error occurs
+     */
+    public static String format(Property prop) throws RepositoryException {
+        return format(prop, false);
+    }
+    
+    /**
+     * Formats the given jcr property to the enhanced docview syntax.
+     * @param prop the jcr property
+     * @param sort if <code>true</code> multivalue properties are sorted
+     * @return the formatted string
+     * @throws RepositoryException if a repository error occurs
+     */
+    public static String format(Property prop, boolean sort)
+            throws RepositoryException {
+        StringBuffer attrValue = new StringBuffer();
+        int type = prop.getType();
+        if (type == PropertyType.BINARY || isAmbiguous(prop)) {
+            attrValue.append("{");
+            attrValue.append(PropertyType.nameFromValue(prop.getType()));
+            attrValue.append("}");
+        }
+        // only write values for non binaries
+        if (prop.getType() != PropertyType.BINARY) {
+            if (prop.getDefinition().isMultiple()) {
+                attrValue.append('[');
+                Value[] values = prop.getValues();
+                if (sort) {
+                    Arrays.sort(values, ValueComparator.getInstance());
+                }
+                for (int i = 0; i < values.length; i++) {
+                    if (i > 0) {
+                        attrValue.append(',');
+                    }
+                    String strValue = ValueHelper.serialize(values[i], false);
+                    switch (prop.getType()) {
+                        case PropertyType.STRING:
+                        case PropertyType.NAME:
+                        case PropertyType.PATH:
+                            escape(attrValue, strValue, true);
+                            break;
+                        default:
+                            attrValue.append(strValue);
+                    }
+                }
+                attrValue.append(']');
+            } else {
+                String strValue = ValueHelper.serialize(prop.getValue(), false);
+                escape(attrValue, strValue, false);
+            }
+        }
+        return attrValue.toString();
+    }
+
+    /**
+     * Escapes the value
+     * @param buf buffer to append to
+     * @param value value to escape
+     * @param isMulti indicates multi value property
+     */
+    protected static void escape(StringBuffer buf, String value, boolean isMulti) {
+        for (int i=0; i<value.length(); i++) {
+            char c = value.charAt(i);
+            if (c == '\\') {
+                buf.append("\\\\");
+            } else if (c == ',' && isMulti) {
+                buf.append("\\,");
+            } else if (i == 0 && !isMulti && (c == '[' || c == '{')) {
+                buf.append('\\').append(c);
+            } else if ( XMLChar.isInvalid(c)) {
+                buf.append("\\u");
+                buf.append(Text.hexTable[(c >> 12) & 15]);
+                buf.append(Text.hexTable[(c >> 8) & 15]);
+                buf.append(Text.hexTable[(c >> 4) & 15]);
+                buf.append(Text.hexTable[c & 15]);
+            } else {
+                buf.append(c);
+            }
+        }
+    }
+    
+    /**
+     * Checks if the type of the given property is ambiguous in respect to it's
+     * property definition. the current implementation just checks some well
+     * known properties.
+     *
+     * @param prop the property
+     * @return type
+     * @throws RepositoryException if a repository error occurs
+     */
+    public static boolean isAmbiguous(Property prop) throws RepositoryException {
+        return prop.getType() != PropertyType.STRING && !UNAMBIGOUS.contains(prop.getName());
+    }
+
+    /**
+     * Sets this property on the given node
+     *
+     * @param node the node
+     * @return <code>true</code> if the value was modified.
+     * @throws RepositoryException if a repository error occurs
+     */
+    public boolean apply(Node node) throws RepositoryException {
+        Property prop = node.hasProperty(name) ? node.getProperty(name) : null;
+        // check if multiple flags are equal
+        if (prop != null && isMulti != prop.getDefinition().isMultiple()) {
+            prop.remove();
+            prop = null;
+        }
+        if (prop != null) {
+            int propType = prop.getType();
+            if (propType != type && (propType != PropertyType.STRING || type != PropertyType.UNDEFINED)) {
+                // never compare if types differ
+                prop = null;
+            }
+        }
+        if (isMulti) {
+            Value[] vs = prop == null ? null : prop.getValues();
+            if (vs != null && vs.length == values.length) {
+                // quick check all values
+                boolean modified = false;
+                for (int i=0; i<vs.length; i++) {
+                    if (!vs[i].getString().equals(values[i])) {
+                        modified = true;
+                    }
+                }
+                if (!modified) {
+                    return false;
+                }
+            }
+            if (type == PropertyType.UNDEFINED) {
+                node.setProperty(name, values);
+            } else {
+                node.setProperty(name, values, type);
+            }
+            // assume modified
+            return true;
+        } else {
+            Value v = prop == null ? null : prop.getValue();
+            if (v == null || !v.getString().equals(values[0])) {
+                try {
+                    if (type == PropertyType.UNDEFINED) {
+                        node.setProperty(name, values[0]);
+                    } else {
+                        node.setProperty(name, values[0], type);
+                    }
+                } catch (ValueFormatException e) {
+                    // forcing string
+                    node.setProperty(name, values[0], PropertyType.STRING);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/FileInputSource.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/FileInputSource.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/FileInputSource.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/FileInputSource.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
+
+/**
+ * Implements a input source that is based on a {@link File}. The path of the
+ * file is used as systemId.
+ * <p/>
+ * Currently only {@link #getByteStream()} is implemented.
+ *
+ */
+public class FileInputSource extends VaultInputSource {
+
+    /**
+     * the file
+     */
+    private final File file;
+
+    /**
+     * possible line feed
+     */
+    private byte[] lineSeparator;
+
+    /**
+     * Creates a new input source that is based on a file.
+     * @param file the file.
+     */
+    public FileInputSource(File file) {
+        super(file.getPath());
+        this.file = file;
+    }
+
+    /**
+     * Sets the linefeed to use. If this is not <code>null</code> the output
+     * stream of the file is wrapped by a {@link LineInputStream} with that
+     * given line feed
+     * @param lineSeparator the linefeed for text
+     */
+    public void setLineSeparator(byte[] lineSeparator) {
+        this.lineSeparator = lineSeparator;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return a {@link FileInputStream} on the internal file.
+     */
+    public InputStream getByteStream() {
+        try {
+            if (lineSeparator != null) {
+                return new LineInputStream(new FileInputStream(file), lineSeparator);
+            } else {
+                return FileUtils.openInputStream(file);
+            }
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the content length of the underlying file.
+     * @return the content length of the underlying file.
+     */
+    public long getContentLength() {
+        return file.length();
+    }
+
+    /**
+     * Returns the last modified date of the underlying file.
+     * @return the last modified date of the underlying file.
+     */
+    public long getLastModified() {
+        return file.lastModified();
+    }
+
+    /**
+     * deletes the underlying file
+     */
+    public void discard() {
+        file.delete();
+        file.deleteOnExit();
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/HtmlProgressListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/HtmlProgressListener.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/HtmlProgressListener.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/HtmlProgressListener.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener;
+
+/**
+ * <code>HtmlProgrressTrackerListener</code>...
+ *
+ */
+public class HtmlProgressListener implements ProgressTrackerListener {
+
+    private final Writer out;
+
+    private boolean noScrollTo;
+
+    private long scrollDelay = 1000;
+
+    private long lastScrolled = 0;
+
+    public HtmlProgressListener(Writer out) {
+        this.out = out;
+    }
+
+    public boolean isNoScrollTo() {
+        return noScrollTo;
+    }
+
+    public HtmlProgressListener setNoScrollTo(boolean noScrollTo) {
+        this.noScrollTo = noScrollTo;
+        return this;
+    }
+
+    public long getScrollDelay() {
+        return scrollDelay;
+    }
+
+    public HtmlProgressListener setScrollDelay(long scrollDelay) {
+        this.scrollDelay = scrollDelay;
+        return this;
+    }
+
+    public void onError(Mode mode, String path, Exception e) {
+        print(mode, "E", path, e.toString());
+    }
+
+    public void onMessage(Mode mode, String action, String path) {
+        print(mode, action, path, null);
+    }
+
+    private void print(Mode mode, String action, String path, String msg) {
+        try {
+            out.write("<span class=\"");
+            out.write(action);
+            out.write("\">");
+            out.write("<b>");
+            out.write(action);
+            out.write("</b>&nbsp;");
+            out.write(path);
+            if (msg != null) {
+                out.write(" (");
+                out.write(msg);
+                out.write(")");
+            }
+            out.write("</span><br>\r\n");
+            if (!noScrollTo) {
+                long now = System.currentTimeMillis();
+                if (now > lastScrolled + scrollDelay) {
+                    lastScrolled = now;
+                    out.write("<script>\r\n");
+                    out.write("window.scrollTo(0, 1000000);\r\n");
+                    out.write("</script>\r\n");
+                }
+            }
+            out.flush();
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/ItemNameComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/ItemNameComparator.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/ItemNameComparator.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/ItemNameComparator.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.util.Comparator;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>ItemNameComparator</code>...
+ */
+public class ItemNameComparator implements Comparator<Item> {
+
+    public static final ItemNameComparator INSTANCE = new ItemNameComparator();
+
+    public int compare(Item o1, Item o2) {
+        try {
+            // sort namespaced first
+            String n1 = o1.getName().toLowerCase();
+            String n2 = o2.getName().toLowerCase();
+            int i1 = n1.indexOf(':');
+            int i2 = n2.indexOf(':');
+            if (i1 >=0 && i2 < 0) {
+                return -1;
+            } else if (i1 < 0 && i2 >=0) {
+                return 1;
+            } else {
+                return n1.compareTo(n2);
+            }
+        } catch (RepositoryException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/JcrConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/JcrConstants.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/JcrConstants.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/JcrConstants.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,343 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+/**
+ * This Interface defines some of the item names that are defined in the
+ * jcr spec 2.0 and some that are used in the cq5 platform, using the default
+ * prefixes 'cq', 'jcr', 'nt' and 'mix'.
+ *
+ * Please note that those prefixes can by redefined by an application using the
+ * {@link javax.jcr.Session#setNamespacePrefix(String, String)} method. As a
+ * result, the constants may not refer to the respective items.
+ */
+public interface JcrConstants {
+
+    // basic jcr 1.0 constants
+
+    /**
+     * jcr:autoCreated
+     */
+    public static final String JCR_AUTOCREATED = "jcr:autoCreated";
+    /**
+     * jcr:baseVersion
+     */
+    public static final String JCR_BASEVERSION = "jcr:baseVersion";
+    /**
+     * jcr:child
+     */
+    public static final String JCR_CHILD = "jcr:child";
+    /**
+     * jcr:childNodeDefinition
+     */
+    public static final String JCR_CHILDNODEDEFINITION = "jcr:childNodeDefinition";
+    /**
+     * jcr:content
+     */
+    public static final String JCR_CONTENT = "jcr:content";
+    /**
+     * jcr:created
+     */
+    public static final String JCR_CREATED = "jcr:created";
+    /**
+     * jcr:data
+     */
+    public static final String JCR_DATA = "jcr:data";
+    /**
+     * jcr:defaultPrimaryType
+     */
+    public static final String JCR_DEFAULTPRIMARYTYPE = "jcr:defaultPrimaryType";
+    /**
+     * jcr:defaultValues
+     */
+    public static final String JCR_DEFAULTVALUES = "jcr:defaultValues";
+    /**
+     * jcr:encoding
+     */
+    public static final String JCR_ENCODING = "jcr:encoding";
+    /**
+     * jcr:frozenMixinTypes
+     */
+    public static final String JCR_FROZENMIXINTYPES = "jcr:frozenMixinTypes";
+    /**
+     * jcr:frozenNode
+     */
+    public static final String JCR_FROZENNODE = "jcr:frozenNode";
+    /**
+     * jcr:frozenPrimaryType
+     */
+    public static final String JCR_FROZENPRIMARYTYPE = "jcr:frozenPrimaryType";
+    /**
+     * jcr:frozenUuid
+     */
+    public static final String JCR_FROZENUUID = "jcr:frozenUuid";
+    /**
+     * jcr:hasOrderableChildNodes
+     */
+    public static final String JCR_HASORDERABLECHILDNODES = "jcr:hasOrderableChildNodes";
+    /**
+     * jcr:isCheckedOut
+     */
+    public static final String JCR_ISCHECKEDOUT = "jcr:isCheckedOut";
+    /**
+     * jcr:isMixin
+     */
+    public static final String JCR_ISMIXIN = "jcr:isMixin";
+    /**
+     * jcr:language
+     */
+    public static final String JCR_LANGUAGE = "jcr:language";
+    /**
+     * jcr:lastModified
+     */
+    public static final String JCR_LASTMODIFIED = "jcr:lastModified";
+    /**
+     * jcr:lockIsDeep
+     */
+    public static final String JCR_LOCKISDEEP = "jcr:lockIsDeep";
+    /**
+     * jcr:lockOwner
+     */
+    public static final String JCR_LOCKOWNER = "jcr:lockOwner";
+    /**
+     * jcr:mandatory
+     */
+    public static final String JCR_MANDATORY = "jcr:mandatory";
+    /**
+     * jcr:mergeFailed
+     */
+    public static final String JCR_MERGEFAILED = "jcr:mergeFailed";
+    /**
+     * jcr:mimeType
+     */
+    public static final String JCR_MIMETYPE = "jcr:mimeType";
+    /**
+     * jcr:mixinTypes
+     */
+    public static final String JCR_MIXINTYPES = "jcr:mixinTypes";
+    /**
+     * jcr:multiple
+     */
+    public static final String JCR_MULTIPLE = "jcr:multiple";
+    /**
+     * jcr:name
+     */
+    public static final String JCR_NAME = "jcr:name";
+    /**
+     * jcr:nodeTypeName
+     */
+    public static final String JCR_NODETYPENAME = "jcr:nodeTypeName";
+    /**
+     * jcr:onParentVersion
+     */
+    public static final String JCR_ONPARENTVERSION = "jcr:onParentVersion";
+    /**
+     * jcr:predecessors
+     */
+    public static final String JCR_PREDECESSORS = "jcr:predecessors";
+    /**
+     * jcr:primaryItemName
+     */
+    public static final String JCR_PRIMARYITEMNAME = "jcr:primaryItemName";
+    /**
+     * jcr:primaryType
+     */
+    public static final String JCR_PRIMARYTYPE = "jcr:primaryType";
+    /**
+     * jcr:propertyDefinition
+     */
+    public static final String JCR_PROPERTYDEFINITION = "jcr:propertyDefinition";
+    /**
+     * jcr:protected
+     */
+    public static final String JCR_PROTECTED = "jcr:protected";
+    /**
+     * jcr:requiredPrimaryTypes
+     */
+    public static final String JCR_REQUIREDPRIMARYTYPES = "jcr:requiredPrimaryTypes";
+    /**
+     * jcr:requiredType
+     */
+    public static final String JCR_REQUIREDTYPE = "jcr:requiredType";
+    /**
+     * jcr:rootVersion
+     */
+    public static final String JCR_ROOTVERSION = "jcr:rootVersion";
+    /**
+     * jcr:sameNameSiblings
+     */
+    public static final String JCR_SAMENAMESIBLINGS = "jcr:sameNameSiblings";
+    /**
+     * jcr:statement
+     */
+    public static final String JCR_STATEMENT = "jcr:statement";
+    /**
+     * jcr:successors
+     */
+    public static final String JCR_SUCCESSORS = "jcr:successors";
+    /**
+     * jcr:supertypes
+     */
+    public static final String JCR_SUPERTYPES = "jcr:supertypes";
+    /**
+     * jcr:system
+     */
+    public static final String JCR_SYSTEM = "jcr:system";
+    /**
+     * jcr:uuid
+     */
+    public static final String JCR_UUID = "jcr:uuid";
+    /**
+     * jcr:valueConstraints
+     */
+    public static final String JCR_VALUECONSTRAINTS = "jcr:valueConstraints";
+    /**
+     * jcr:versionHistory
+     */
+    public static final String JCR_VERSIONHISTORY = "jcr:versionHistory";
+    /**
+     * jcr:versionLabels
+     */
+    public static final String JCR_VERSIONLABELS = "jcr:versionLabels";
+    /**
+     * jcr:versionStorage
+     */
+    public static final String JCR_VERSIONSTORAGE = "jcr:versionStorage";
+    /**
+     * jcr:versionableUuid
+     */
+    public static final String JCR_VERSIONABLEUUID = "jcr:versionableUuid";
+
+    /**
+     * Pseudo property jcr:path used with query results
+     */
+    public static final String JCR_PATH = "jcr:path";
+    /**
+     * Pseudo property jcr:score used with query results
+     */
+    public static final String JCR_SCORE = "jcr:score";
+
+    /**
+     * mix:lockable
+     */
+    public static final String MIX_LOCKABLE = "mix:lockable";
+    /**
+     * mix:referenceable
+     */
+    public static final String MIX_REFERENCEABLE = "mix:referenceable";
+    /**
+     * mix:versionable
+     */
+    public static final String MIX_VERSIONABLE = "mix:versionable";
+    /**
+     * nt:base
+     */
+    public static final String NT_BASE = "nt:base";
+    /**
+     * nt:childNodeDefinition
+     */
+    public static final String NT_CHILDNODEDEFINITION = "nt:childNodeDefinition";
+    /**
+     * nt:file
+     */
+    public static final String NT_FILE = "nt:file";
+    /**
+     * nt:folder
+     */
+    public static final String NT_FOLDER = "nt:folder";
+    /**
+     * nt:frozenNode
+     */
+    public static final String NT_FROZENNODE = "nt:frozenNode";
+    /**
+     * nt:hierarchyNode
+     */
+    public static final String NT_HIERARCHYNODE = "nt:hierarchyNode";
+    /**
+     * nt:linkedFile
+     */
+    public static final String NT_LINKEDFILE = "nt:linkedFile";
+    /**
+     * nt:nodeType
+     */
+    public static final String NT_NODETYPE = "nt:nodeType";
+    /**
+     * nt:propertyDefinition
+     */
+    public static final String NT_PROPERTYDEFINITION = "nt:propertyDefinition";
+    /**
+     * nt:query
+     */
+    public static final String NT_QUERY = "nt:query";
+    /**
+     * nt:resource
+     */
+    public static final String NT_RESOURCE = "nt:resource";
+    /**
+     * nt:unstructured
+     */
+    public static final String NT_UNSTRUCTURED = "nt:unstructured";
+    /**
+     * nt:version
+     */
+    public static final String NT_VERSION = "nt:version";
+    /**
+     * nt:versionHistory
+     */
+    public static final String NT_VERSIONHISTORY = "nt:versionHistory";
+    /**
+     * nt:versionLabels
+     */
+    public static final String NT_VERSIONLABELS = "nt:versionLabels";
+    /**
+     * nt:versionedChild
+     */
+    public static final String NT_VERSIONEDCHILD = "nt:versionedChild";
+
+    // future JSR283 item and node type names
+
+    /**
+     * jcr:title
+     */
+    public static final String JCR_TITLE = "jcr:title";
+    /**
+     * jcr:description
+     */
+    public static final String JCR_DESCRIPTION = "jcr:description";
+    /**
+     * jcr:createdBy
+     */
+    public static final String JCR_CREATED_BY = "jcr:createdBy";
+    /**
+     * jcr:lastModifiedBy
+     */
+    public static final String JCR_LAST_MODIFIED_BY = "jcr:lastModifiedBy";
+    /**
+     * mix:title
+     */
+    public static final String MIX_TITLE = "mix:title";
+    /**
+     * mix:created
+     */
+    public static final String MIX_CREATED = "mix:created";
+    /**
+     * mix:lastModified
+     */
+    public static final String MIX_LAST_MODIFIED = "mix:lastModified";
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineInputStream.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineInputStream.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineInputStream.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides an input stream wrapper that detects line feed sequences and 
+ * replaces them by new ones.
+ *
+ */
+public class LineInputStream extends InputStream {
+
+    public static final byte[] LS_UNIX = new byte[]{0x0a};
+
+    public static final byte[] LS_WINDOWS = new byte[]{0x0d, 0x0a};
+
+    public static final byte[] LS_NATIVE = System.getProperty("line.separator").getBytes();
+
+    private byte[] buffer = new byte[8192];
+
+    private byte[] lineFeed = LS_NATIVE;
+
+    private byte[] lineSpool;
+
+    private int pos = 0;
+
+    private int end = 0;
+
+    private static final char STATE_INIT = ' ';
+    private static final char STATE_CR = 'c';
+    private static final char STATE_LF = 'l';
+    private static final char STATE_CRLF = 'f';
+
+    private char state = STATE_INIT;
+
+    boolean isEof = false;
+
+    private byte[] spool;
+
+    private int spoolPos = 0;
+
+    private final InputStream in;
+
+    public LineInputStream(InputStream in, byte[] ls) {
+        this.in = in;
+        if (ls != null) {
+            lineFeed = ls;
+        }
+        lineSpool = new byte[lineFeed.length + 1];
+        System.arraycopy(lineFeed, 0, lineSpool, 0, lineFeed.length);
+    }
+
+    private int fillBuffer() throws IOException {
+        int ret = in.read(buffer, end, buffer.length - end);
+        if (ret >= 0) {
+            end += ret;
+        } else {
+            isEof = true;
+        }
+        return ret;
+    }
+
+    public int read() throws IOException {
+        final byte[] one = new byte[1];
+        if (read(one) == -1) {
+            return -1;
+        }
+        return one[0];
+    }
+
+    public int read(byte b[], int off, int len) throws IOException {
+        if (isEof) {
+            if (spool == null) {
+                if (state != STATE_INIT) {
+                    spool = lineFeed;
+                    state = STATE_INIT;
+                } else {
+                    return -1;
+                }
+            }
+        }
+        int total = 0;
+        while (total < len) {
+            if (spool != null) {
+                b[off+(total++)] = spool[spoolPos++];
+                if (spoolPos == spool.length) {
+                    spool = null;
+                    spoolPos = 0;
+                }
+            } else {
+                if (pos == end) {
+                    int ret = fillBuffer();
+                    if (ret == 0 && pos == end) {
+                        // in this case we didn't get more, so flush
+                        pos = end = 0;
+                        continue;
+                    } else if (ret == -1) {
+                        break;
+                    }
+                }
+                byte c = buffer[pos++];
+                if (c == 0x0a) {
+                    switch (state) {
+                        case STATE_INIT:
+                            state = STATE_LF;
+                            break;
+                        case STATE_CR:
+                            state = STATE_CRLF;
+                            break;
+                        case STATE_LF:
+                            spool = lineFeed;
+                            break;
+                        case STATE_CRLF:
+                            spool = lineFeed;
+                            state = STATE_LF;
+                    }
+                } else if (c == 0x0d) {
+                    switch (state) {
+                        case STATE_INIT:
+                            state = STATE_CR;
+                            break;
+                        case STATE_LF:
+                            state = STATE_CRLF;
+                            break;
+                        case STATE_CR:
+                            spool = lineFeed;
+                            break;
+                        case STATE_CRLF:
+                            spool = lineFeed;
+                            state = STATE_CR;
+                    }
+                } else {
+                    if (state != STATE_INIT) {
+                        spool = lineSpool;
+                        lineSpool[lineSpool.length - 1] = c;
+                        state = STATE_INIT;
+                    } else {
+                        b[off + (total++)] = c;
+                    }
+                }
+            }
+        }
+        return total;
+    }
+
+    public void close() throws IOException {
+        in.close();
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineOutputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineOutputStream.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineOutputStream.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/LineOutputStream.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Provides an output stream wrapper that detects line feed sequences and
+ * replaces them by new ones.
+ *
+ */
+public class LineOutputStream extends OutputStream {
+
+    public static final byte[] LS_BINARY = null;
+
+    public static final byte[] LS_UNIX = new byte[]{0x0a};
+
+    public static final byte[] LS_WINDOWS = new byte[]{0x0d, 0x0a};
+
+    public static final byte[] LS_NATIVE = System.getProperty("line.separator").getBytes();
+
+    private byte[] buffer = new byte[8192];
+
+    private byte[] lineFeed = LS_NATIVE;
+
+    private int pos = 0;
+
+    private static final char STATE_INIT = ' ';
+    private static final char STATE_CR = 'c';
+    private static final char STATE_LF = 'l';
+    private static final char STATE_CRLF = 'f';
+
+    private char state = STATE_INIT;
+
+    private final OutputStream out;
+
+    public LineOutputStream(OutputStream out, byte[] ls) {
+        this.out = out;
+        if (ls != null) {
+            this.lineFeed = ls;
+        }
+    }
+
+    public void write(int b) throws IOException {
+        if (b == 0x0a) {
+            switch (state) {
+                case STATE_INIT:
+                    state = STATE_LF;
+                    break;
+                case STATE_CR:
+                    state = STATE_CRLF;
+                    break;
+                case STATE_LF:
+                    flush(true);
+                    state = STATE_LF;
+                    break;
+                case STATE_CRLF:
+                    flush(true);
+                    state = STATE_LF;
+            }
+        } else if (b == 0x0d) {
+            switch (state) {
+                case STATE_INIT:
+                    state = STATE_CR;
+                    break;
+                case STATE_LF:
+                    state = STATE_CRLF;
+                    break;
+                case STATE_CR:
+                    flush(true);
+                    state = STATE_CR;
+                    break;
+                case STATE_CRLF:
+                    flush(true);
+                    state = STATE_CR;
+            }
+        } else {
+            if (state != STATE_INIT) {
+                flush(true);
+                state = STATE_INIT;
+            }
+            if (pos == buffer.length) {
+                flush();
+            }
+            buffer[pos++] = (byte) (b & 0xff);
+        }
+    }
+
+    public void flush(boolean addLF) throws IOException {
+        flush();
+        if (addLF) {
+            out.write(lineFeed);
+        }
+        out.flush();
+    }
+
+    public void flush() throws IOException {
+        out.write(buffer, 0, pos);
+        pos = 0;
+        out.flush();
+    }
+
+    public void close() throws IOException {
+        // check for pending lfs
+        flush(state != STATE_INIT);
+        out.close();
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MD5.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MD5.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MD5.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MD5.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * <code>MD5</code>...
+ */
+public class MD5 {
+
+    private final long msb;
+
+    private final long lsb;
+
+    public MD5(long msb, long lsb) {
+        this.msb = msb;
+        this.lsb = lsb;
+    }
+
+    public MD5(String str) {
+        if (str.length() != 32) {
+            throw new IllegalArgumentException("invalid string length " + str.length());
+        }
+        msb = (Long.parseLong(str.substring(0, 8), 16) << 32)
+                + (Long.parseLong(str.substring(8, 16), 16));
+        lsb = (Long.parseLong(str.substring(16, 24), 16) << 32)
+                + (Long.parseLong(str.substring(24, 32), 16));
+    }
+
+    public MD5(byte[] bytes) {
+        if (bytes.length != 16) {
+            throw new IllegalArgumentException("invalid bytes length " + bytes.length);
+        }
+        msb = getLong(bytes, 0);
+        lsb = getLong(bytes, 8);
+    }
+
+    public long[] getLongs() {
+        return new long[]{msb, lsb};
+    }
+
+    public long getMsb() {
+        return msb;
+    }
+
+    public long getLsb() {
+        return lsb;
+    }
+
+    public byte[] getBytes() {
+        byte[] buf = new byte[16];
+        setLong(buf, 0, msb);
+        setLong(buf, 8, lsb);
+        return buf;
+    }
+
+    public static MD5 digest(InputStream in) throws IOException {
+        try {
+            MessageDigest md;
+            try {
+                md = MessageDigest.getInstance("md5");
+            } catch (NoSuchAlgorithmException e) {
+                throw new IllegalArgumentException(e.toString());
+            }
+            byte[] buffer = new byte[8192];
+            int read;
+            while ((read = in.read(buffer)) > 0) {
+                md.update(buffer, 0, read);
+            }
+            return new MD5(md.digest());
+        } finally {
+            in.close();
+        }
+    }
+
+    public static MD5 digest(File file) throws IOException {
+        return digest(new FileInputStream(file));
+    }
+
+    public String toString() {
+        return String.format("%016x%016x", msb, lsb);
+    }
+
+    public int hashCode() {
+        return (int)((msb >> 32) ^ msb ^ (lsb >> 32) ^ lsb);
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        MD5 md5 = (MD5) o;
+        return lsb == md5.lsb && msb == md5.msb;
+    }
+
+    private static long getLong(byte[] b, int offs) {
+        return ((long)  (b[offs] & 0xFF) << 56) +
+                ((long) (b[1 + offs] & 0xFF) << 48) +
+                ((long) (b[2 + offs] & 0xFF) << 40) +
+                ((long) (b[3 + offs] & 0xFF) << 32) +
+                ((long) (b[4 + offs] & 0xFF) << 24) +
+                ((long) (b[5 + offs] & 0xFF) << 16) +
+                ((long) (b[6 + offs] & 0xFF) << 8) +
+                ((long) (b[7 + offs] & 0xFF));
+    }
+
+    private static void setLong(byte[] b, int offs, long v) {
+        b[offs]   = (byte) ((v >>> 56) & 0xFF);
+        b[offs+1] = (byte) ((v >>> 48) & 0xFF);
+        b[offs+2] = (byte) ((v >>> 40) & 0xFF);
+        b[offs+3] = (byte) ((v >>> 32) & 0xFF);
+        b[offs+4] = (byte) ((v >>> 24) & 0xFF);
+        b[offs+5] = (byte) ((v >>> 16) & 0xFF);
+        b[offs+6] = (byte) ((v >>>  8) & 0xFF);
+        b[offs+7] = (byte) ((v >>>  0) & 0xFF);
+    }
+
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MimeTypes.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MimeTypes.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MimeTypes.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/MimeTypes.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * <code>MimeTypes</code> contains a mapping from extensions to mime types.
+ *
+ */
+public class MimeTypes {
+
+    /**
+     * constant for {@value}
+     */
+    public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
+
+    /**
+     * mapping from content-type to {@link MimeType}s.
+     */
+    private static final HashMap<String, MimeType> byMimeType = new HashMap<String, MimeType>();
+
+    /**
+     * mapping from extension to {@link MimeType}s.
+     */
+    private static final HashMap<String, MimeType> byExtension = new HashMap<String, MimeType>();
+
+    static {
+        // add some default mappings
+        addMapping(false, "text/plain", "txt", "jsp", "jspx", "jspf", "ecma", "esp", "xsl", "xslt", "dtd", "properties", "tld" ,"php", "rb", "bnd");
+        addMapping(false, "text/cnd"  , "cnd");
+        addMapping(false, "text/x-java-source" , "java");
+        addMapping(true,  "application/java-vm" , "class");
+        addMapping(false, "text/html" , "html", "htm");
+        addMapping(false, "text/xml"  , "xml");
+        addMapping(false, "text/css"  , "css", "less");
+        addMapping(false, "text/calendar", "ics");
+        addMapping(false, "image/svg+xml", "svg");
+        addMapping(false, "application/xliff+xml"  , "xliff");
+        addMapping(true,  "image/gif" , "gif");
+        addMapping(true,  "image/png" , "png");
+        addMapping(true,  "image/jpeg", "jpg", "jpeg");
+        addMapping(true,  "image/jpg" , "jpg", "jpeg"); // this is for compatibility reasons
+        addMapping(false, "application/json", "json");
+        addMapping(true,  "application/java-archive", "jar");
+        addMapping(false, "application/javascript", "js");
+        addMapping(false, "application/ecmascript", "ecma");
+        addMapping(false, "application/x-javascript", "js"); // discouraged per RFC-4329
+        addMapping(true,  "application/pdf", "pdf");
+        addMapping(true,  "application/x-shockwave-flash", "swf");
+        addMapping(true,  "application/zip", "zip");
+        addMapping(true,  "image/vnd.microsoft.icon", "ico");
+        addMapping(true,  "application/x-font-woff", "woff");
+        addMapping(true,  "application/vnd.ms-fontobject", "eot");
+    }
+
+    /**
+     * internally add a mapping to the static defined ones
+     * @param binary binary flag
+     * @param mimeType the content type
+     * @param ext extensions
+     */
+    private static void addMapping(boolean binary, String mimeType, String ... ext) {
+        if (byMimeType.containsKey(mimeType)) {
+            throw new IllegalArgumentException("MimeType already registered:" + mimeType);
+        }
+        MimeType mt = new MimeType(mimeType, binary, ext);
+        byMimeType.put(mimeType, mt);
+        for (String e: ext) {
+            if (!byExtension.containsKey(e)) {
+                // only register default mime type
+                byExtension.put(e, mt);
+            }
+        }
+    }
+
+    /**
+     * Retrieve the mimetype for the given extension or name
+     * @param name the name
+     * @return the mimetype or <code>null</code>
+     */
+    public static String getMimeType(String name) {
+        return getMimeType(name, null);
+    }
+
+    /**
+     * Retrieve the mimetype for the given extension or name
+     * @param name the name
+     * @param defaultType type to return if no mapping is found.
+     * @return the mimetype or <code>null</code>
+     */
+    public static String getMimeType(String name, String defaultType) {
+        name = name.substring(name.lastIndexOf('.') + 1);
+        MimeType mt = byExtension.get(name);
+        if (mt == null) {
+            return defaultType;
+        } else {
+            return mt.mimeType;
+        }
+    }
+
+    /**
+     * Retrieve the default extension for the given mime type
+     * @param mimeType the mime type
+     * @return the extension or null
+     */
+    public static String getExtension(String mimeType) {
+        MimeType mt = byMimeType.get(mimeType);
+        if (mt == null) {
+            return null;
+        } else {
+            return mt.defaultExt;
+        }
+    }
+
+    /**
+     * checks if the given mimetype denotes binary content
+     * @param mimeType the mime type
+     * @return <code>true</code> if binary or if <code>mimeType</code> is <code>null</code>
+     */
+    public static boolean isBinary(String mimeType) {
+        if (mimeType == null) {
+            return true;
+        }
+        if (mimeType.startsWith("text/")) {
+            return false;
+        }
+        MimeType mt = byMimeType.get(mimeType);
+        return mt == null || mt.isBinary();
+    }
+
+    /**
+     * Checks if the given mime type is mapped to the extension
+     * @param mimeType the mime type
+     * @param ext the extension
+     * @return <code>true</code> if the given mime type contains that extension
+     */
+    public static boolean hasExtension(String mimeType, String ext) {
+        MimeType mt = byMimeType.get(mimeType);
+        return mt != null && mt.extensions.contains(ext);
+    }
+
+    public static boolean matches(String name, String mimeType, String defaultType) {
+        name = name.substring(name.lastIndexOf('.') + 1);
+        MimeType mt = byExtension.get(name);
+        if (mt != null && mt.mimeType.equals(mimeType)) {
+            return true;
+        }
+        // try reverse mapping
+        mt = byMimeType.get(mimeType);
+        if (mt != null && mt.extensions.contains(name)) {
+            return true;
+        }
+        return mimeType.equals(defaultType);
+    }
+
+    /**
+     * holds the mime type to extension mappings
+     */
+    private static class MimeType {
+
+        /**
+         * the mime type
+         */
+        private final String mimeType;
+
+        /**
+         * the default extension
+         */
+        private final String defaultExt;
+
+        /**
+         * set of all extensions
+         */
+        private final HashSet<String> extensions = new HashSet<String>();
+
+        /**
+         * binary flag
+         */
+        private final boolean binary;
+
+        /**
+         * creates a new mapping
+         * @param mimeType the mime type
+         * @param binary binary flag
+         * @param ext the extensions
+         */
+        public MimeType(String mimeType, boolean binary, String ... ext) {
+            this.mimeType = mimeType;
+            this.binary = binary;
+            this.defaultExt = ext[0];
+            extensions.addAll(Arrays.asList(ext));
+        }
+
+        /**
+         * Returns <code>true</code> if this is a binary mime type
+         * @return <code>true</code> if binary.
+         *
+         */
+        public boolean isBinary() {
+            return binary;
+        }
+    }
+}

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/NodeNameComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/NodeNameComparator.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/NodeNameComparator.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/NodeNameComparator.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.util.Comparator;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>ItemNameComparator</code>...
+ */
+public class NodeNameComparator implements Comparator<Node> {
+
+    public static final NodeNameComparator INSTANCE = new NodeNameComparator();
+
+    public int compare(Node o1, Node o2) {
+        try {
+            // sort namespaced first
+            String n1 = o1.getName().toLowerCase();
+            String n2 = o2.getName().toLowerCase();
+            int i1 = n1.indexOf(':');
+            int i2 = n2.indexOf(':');
+            if (i1 >=0 && i2 < 0) {
+                return -1;
+            } else if (i1 < 0 && i2 >=0) {
+                return 1;
+            } else if (n1.equals(n2)) {
+                // compare indexes for SNS
+                return o1.getIndex() - o2.getIndex();
+            } else {
+                return n1.compareTo(n2);
+            }
+        } catch (RepositoryException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathComparator.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathComparator.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathComparator.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.util.Comparator;
+
+/**
+ * <code>PathComparator</code>...
+ *
+ */
+public class PathComparator implements Comparator<String> {
+
+    private final char separator;
+
+    private boolean reverse;
+
+    public PathComparator() {
+        separator = '/';
+    }
+
+    public PathComparator(boolean reverse) {
+        separator = '/';
+        this.reverse = reverse;
+    }
+
+    public PathComparator(char separator) {
+        this.separator = separator;
+    }
+
+    public PathComparator(char separator, boolean reverse) {
+        this.separator = separator;
+        this.reverse = reverse;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Compared to the {@link String#compareTo(String)} it handles the '/'
+     * differently giving it the highest priority so that:
+     *
+     * "/a" < "/b"
+     * "/a1foo" < "/a/foo"
+     */
+    public int compare(String o1, String o2) {
+        if (o1.equals(o2)) {
+            return 0;
+        }
+        int last0 = 0;
+        int last1 = 0;
+        int i0 = o1.indexOf(separator, 1);
+        int i1 = o2.indexOf(separator, 1);
+        while (i0 > 0 && i1 > 0) {
+            int c = o1.substring(last0, i0).compareTo(o2.substring(last1, i1));
+            if (c != 0) {
+                return reverse ? -c : c;
+            }
+            last0 = i0;
+            last1 = i1;
+            i0 = o1.indexOf(separator, i0 + 1);
+            i1 = o2.indexOf(separator, i1 + 1);
+        }
+        int ret;
+        if (i0 > 0) {
+            ret = 1;
+        } else if (i1 > 0) {
+            ret = -1;
+        } else {
+            // compare last segment
+            ret = o1.substring(last0).compareTo(o2.substring(last1));
+        }
+        return reverse ? -ret : ret;
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathUtil.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathUtil.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PathUtil.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.File;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>PathUtil</code>...
+ *
+ */
+public class PathUtil {
+
+    /**
+     * make a canonical path. removes all /./ and /../ and multiple slashes.
+     * @param parent the parent path (can be <code>null</code>)
+     * @param path the path to resolve
+     * @return the canonicalized path
+     */
+    public static String[] makePath(String[] parent, String path) {
+        if (path == null || path.equals("") || path.equals(".")) {
+            return parent;
+        }
+        // compose parent and path
+        boolean isAbsolute = false;
+        String[] composed = Text.explode(path, '/');
+        if (path.charAt(0) == '/') {
+            isAbsolute = true;
+        } else {
+            if (parent != null && parent.length > 0) {
+                int off = 0;
+                if (parent[0].equals("/")) {
+                    isAbsolute = true;
+                    off = 1;
+                }
+                String[] c = new String[parent.length - off + composed.length];
+                System.arraycopy(parent, off, c, 0, parent.length - off);
+                System.arraycopy(composed, 0, c, parent.length - off, composed.length);
+                composed = c;
+            }
+        }
+        // canonicalize
+        int dst = 0;
+        boolean startsWithParent = false;
+        for (int i=0; i<composed.length; i++) {
+            String element = composed[i];
+            if (element.equals(".")) {
+                // skip
+            } else if (element.equals("..")) {
+                if (dst == 0) {
+                    startsWithParent = true;
+                }
+                if (startsWithParent) {
+                    composed[dst++] = element;
+                } else {
+                    dst--;
+                }
+            } else {
+                composed[dst++] = element;
+            }
+        }
+        // truncate
+        if (isAbsolute) {
+            String[] ret = new String[dst + 1];
+            System.arraycopy(composed, 0, ret, 1, dst);
+            ret[0] = "/";
+            return ret;
+        } else if (dst == composed.length) {
+            return composed;
+        } else {
+            String[] ret = new String[dst];
+            System.arraycopy(composed, 0, ret, 0, dst);
+            return ret;
+        }
+    }
+
+    public static String makePath(String parent, String relPath) {
+        String[] ret = makePath(Text.explode(parent, '/'), relPath);
+        return "/" + Text.implode(ret, "/");
+    }
+
+    public static File getRelativeFile(File parent, File file) {
+        return new File(getRelativeFilePath(parent.getPath(), file.getPath()));
+    }
+    
+    public static String getRelativePath(String parent, String path) {
+        return getRelativeFilePath(parent, path, "/");
+    }
+
+    public static String getRelativeFilePath(String cwd, String path) {
+        return getRelativeFilePath(cwd, path, Constants.FS_NATIVE);
+    }
+
+    public static String getRelativeFilePath(String cwd, String path, String separator) {
+        if (cwd.equals(path)) {
+            return ".";
+        }
+        if (!path.startsWith(separator)) {
+            // check for windows abs paths
+            if (path.length() < 2 || path.charAt(1) != ':' || path.charAt(2) != '\\') {
+                return path;
+            }
+        }
+        String[] p1 = Text.explode(cwd, separator.charAt(0));
+        String[] p2 = Text.explode(path, separator.charAt(0));
+        // search common ancestor
+        int i=0;
+        while (i<p1.length && i<p2.length && p1[i].equals(p2[i])) {
+            i++;
+        }
+        StringBuffer buf = new StringBuffer();
+        String delim = "";
+        // go p1.length - i levels up to the common ancestor
+        for (int j = i; j<p1.length; j++) {
+            buf.append(delim).append("..");
+            delim = separator;
+        }
+        // append rest of path
+        while (i<p2.length) {
+            buf.append(delim).append(p2[i++]);
+            delim = separator;
+        }
+        return buf.toString();
+    }
+
+    public static String append(String parent, String relPath) {
+        if (relPath == null || relPath.length() == 0) {
+            return parent == null ? "" : parent;
+        }
+        StringBuffer ret = new StringBuffer();
+        if (parent != null) {
+            ret.append(parent);
+        }
+        if (ret.length() > 0 && ret.charAt(ret.length()-1) != '/') {
+            ret.append('/');
+        }
+        ret.append(relPath);
+        return ret.toString();
+    }
+    
+    public static int getDepth(String path) {
+        // assume valid absolute path
+        int len = path.length();
+        if (len <=1) {
+            return 0;
+        }
+        int depth = 1;
+        for (int i=1; i<len; i++) {
+            if (path.charAt(i) == '/') {
+                depth++;
+            }
+        }
+        return depth;
+    }
+
+    public static String getPath(Node parent, String relPath) throws RepositoryException {
+        String path = parent.getPath();
+        if (relPath.length() > 0) {
+            if (path.endsWith("/")) {
+                path += relPath;
+            } else {
+                path += "/" + relPath;
+            }
+        }
+        return path;
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/PlatformNameFormat.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+/**
+ * Implements a repository to platform name formatter. Illegal characters a
+ * generally escaped using the url escaping format, i.e. replacing the char
+ * by a '%' hex(char) sequence. special treatment is used for the ':' char
+ * since it's used quite often as namespace prefix separator. the
+ * PREFIX ':' NAME sequence is replaced by '_' PREFIX '_' NAME. item names
+ * that would generate the same pattern are escaped with an extra leading '_'.
+ *
+ * examples:
+ *
+ * +-------------------+----------------------+----+----+
+ * | repository name   | platform name        | pp | sp |
+ * +-------------------+----------------------+----+----+
+ * | test.jpg          | test.jpg             | -1 | -1 |
+ * | cq:content        | _cq_content          |  2 | -1 |
+ * | cq:test_image.jpg | _cq_test_image.jpg   |  2 |  7 |
+ * | test_image.jpg    | test_image.jpg       | -1 |  4 |
+ * | _testimage.jpg    | _testimage.jpg       | -1 |  0 |
+ * | _test_image.jpg   | __test_image.jpg     | -1 |  0 |
+ * +-------------------+----------------------+----+----+
+ * | cq:test:image.jpg | _cq_test%3aimage.jpg |  2 | -1 |
+ * | _cq_:test.jpg     | __cq_%3atest.jpg     |  4 |  0 |
+ * | _cq:test.jpg      | __cq%3atest.jpg      |  3 |  0 |
+ * | cq_:test.jpg      | cq_%3atest.jpg       |  3 |  2 |
+ * +-------------------+----------------------+----+----+
+ *
+ * note for the 2nd set of examples the cases are very rare and justify the
+ * ugly '%' escaping.
+ *
+ */
+public class PlatformNameFormat {
+
+    /**
+     * Returns the platform name for a given repository name. Unsupported
+     * characters are URL escaped (i.e. %xx).
+     *
+     * Note: Forward slashes '/' are not escaped since they never occur in a
+     * jcr name. so this method can also be used to encode paths.
+     *
+     * @param repositoryName the repository name
+     * @return the (escaped) platform name.
+     */
+    public static String getPlatformName(String repositoryName) {
+        StringBuffer buf = new StringBuffer("_");
+        boolean escapeColon = false;
+        boolean useUnderscore = false;
+        int numUnderscore = 0;
+        for (int i=0; i<repositoryName.length(); i++) {
+            char c = repositoryName.charAt(i);
+            switch (c) {
+                 case':':
+                     if (!escapeColon && i>0) {
+                         // pure prefix
+                         escapeColon = true;
+                         useUnderscore = true;
+                         numUnderscore = 2;
+                         buf.append('_');
+                     } else {
+                         buf.append("%3a");
+                     }
+                     break;
+                 case '_':
+                     if (i==0) {
+                         useUnderscore = true;
+                     }
+                     numUnderscore++;
+                     escapeColon=true;
+                     buf.append(c);
+                     break;
+                 case'\\':
+                 case'<':
+                 case'>':
+                 case'|':
+                 case'\"':
+                 case '/':
+                 case'?':
+                 case'%':
+                     buf.append('%');
+                     buf.append(Character.forDigit(c / 16, 16));
+                     buf.append(Character.forDigit(c % 16, 16));
+                     break;
+                 default:
+                     buf.append(c);
+             }
+        }
+        if (useUnderscore && numUnderscore > 1) {
+            return buf.toString();
+        } else {
+            return buf.substring(1);
+        }
+    }
+
+    /**
+     * Returns the platform path for the given repository one.
+     * @param repoPath the repository path
+     * @return the platform path
+     */
+    public static String getPlatformPath(String repoPath) {
+        String[] elems = Text.explode(repoPath, '/', true);
+        for (int i=0; i<elems.length; i++) {
+            if (elems[i].length() > 0) {
+                elems[i] = getPlatformName(elems[i]);
+            }
+        }
+        return Text.implode(elems, "/");
+    }
+
+    /**
+     * Returns the repository name for a given platform name.
+     *
+     * @param platformName the platform name
+     * @return the (unescaped) repository name.
+     */
+    public static String getRepositoryName(String platformName) {
+        StringBuffer buffer = new StringBuffer("_");
+        boolean firstUnderscore = false;
+        for (int i=0; i<platformName.length(); i++) {
+            char c = platformName.charAt(i);
+            if (c == '%') {
+                if (platformName.length() > i+2) {
+                    int a = Character.digit(platformName.charAt(++i), 16);
+                    int b = Character.digit(platformName.charAt(++i), 16);
+                    c = (char) (a * 16 + b);
+                }
+            } else if (c == '_') {
+                if (i==0) {
+                    firstUnderscore = true;
+                    if (platformName.length()>1) {
+                        c = platformName.charAt(++i);
+                        if (c == '_') {
+                            buffer.append('_');
+                            firstUnderscore = false;
+                        } else {
+                            buffer.append(c);
+                        }
+                    }
+                    continue;
+                } else if (firstUnderscore) {
+                    c = ':';
+                    firstUnderscore = false;
+                }
+            }
+            buffer.append(c);
+        }
+        if (firstUnderscore) {
+            // pending underscore
+            return buffer.toString();
+        } else {
+            return buffer.substring(1);
+        }
+    }
+
+    /**
+     * Returns the repository path for the given platform one.
+     * @param path the platform path
+     * @return the repository path
+     */
+    public static String getRepositoryPath(String path) {
+        String[] elems = Text.explode(path, '/', true);
+        for (int i=0; i<elems.length; i++) {
+            if (elems[i].length() > 0) {
+                elems[i] = getRepositoryName(elems[i]);
+            }
+        }
+        return Text.implode(elems, "/");
+    }
+
+    /**
+     * Returns the repository path for the given platform one.
+     * @param path the platform path
+     * @param respectDotDir if <code>true</code>, all ".dir" are removed.
+     * @return the repository path
+     */
+    public static String getRepositoryPath(String path, boolean respectDotDir) {
+        String[] elems = Text.explode(path, '/', true);
+        for (int i=0; i<elems.length; i++) {
+            if (elems[i].length() > 0) {
+                if (respectDotDir && elems[i].endsWith(".dir")) {
+                    elems[i] = getRepositoryName(elems[i].substring(0, elems[i].length() - 4));
+                } else {
+                    elems[i] = getRepositoryName(elems[i]);
+                }
+            }
+        }
+        return Text.implode(elems, "/");
+    }
+
+
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityDefaultHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityDefaultHandler.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityDefaultHandler.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityDefaultHandler.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Default handler with special entity resolver that handles all entity resolution requests by returning an empty input
+ * source. This is to prevent "Arbitrary DTD inclusion in XML parsing".
+ */
+public class RejectingEntityDefaultHandler extends DefaultHandler {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(RejectingEntityDefaultHandler.class);
+
+    @Override
+    public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
+        log.warn("Rejecting external entity loading with publicId={} systemId={}", publicId, systemId);
+        return new InputSource(new StringReader(""));
+    }
+}
\ No newline at end of file

Added: jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityResolver.java?rev=1512568&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityResolver.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-core/src/main/java/org/apache/jackrabbit/vault/util/RejectingEntityResolver.java Sat Aug 10 05:53:42 2013
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.vault.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Entity resolver that handles all entity resolution requests by returning an empty input source.
+ * This is to prevent "Arbitrary DTD inclusion in XML parsing".
+ */
+public class RejectingEntityResolver implements EntityResolver {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(RejectingEntityResolver.class);
+
+    public InputSource resolveEntity(String publicId, String systemId)
+            throws SAXException, IOException {
+        log.warn("Rejecting external entity loading with publicId={} systemId={}", publicId, systemId);
+        return new InputSource(new StringReader(""));
+    }
+
+}
\ No newline at end of file