blob: 33a3d9ac3af048d2732ad3cc0dfa823fd7f76232 [file] [log] [blame]
/*
* 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 org.apache.jackrabbit.util.Text;
/**
* Implements a repository to platform name formatter.
*
* <p>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 '_'.
*
* <p>Examples:
*
* <pre>
* +-------------------+----------------------+----+----+
* | 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 |
* +-------------------+----------------------+----+----+
* </pre>
*
* 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) {
StringBuilder buf = new StringBuilder("_");
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");
escapeColon = true;
}
break;
case '_':
if (i==0) {
useUnderscore = true;
}
numUnderscore++;
escapeColon=true;
buf.append(c);
break;
case'\\':
case'<':
case'>':
case'|':
case'\"':
case '/':
case'?':
case'%':
addEscapedCharacter(buf, c);
break;
default:
buf.append(c);
}
}
if (useUnderscore && numUnderscore > 1) {
return buf.toString();
} else {
return buf.substring(1);
}
}
public static void addEscapedCharacter(StringBuilder buf, char c) {
buf.append('%');
buf.append(Character.forDigit(c / 16, 16));
buf.append(Character.forDigit(c % 16, 16));
}
/**
* 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) {
StringBuilder buffer = new StringBuilder("_");
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}, 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, "/");
}
}