summaryrefslogtreecommitdiff
path: root/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java')
-rw-r--r--subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java b/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
new file mode 100644
index 0000000..9dd684d
--- /dev/null
+++ b/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
@@ -0,0 +1,1077 @@
+/**
+ * @copyright
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl;
+
+import org.apache.subversion.javahl.callback.*;
+import org.apache.subversion.javahl.types.*;
+import org.apache.subversion.javahl.util.*;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class SVNUtil
+{
+ //
+ // Global configuration
+ //
+ private static final ConfigLib configLib = new ConfigLib();
+
+ /**
+ * Enable storing authentication credentials in Subversion's
+ * standard credentials store in the configuration directory and
+ * system-specific secure locations.
+ * <p>
+ * The standard credentials store is enabled by default.
+ * <p>
+ * This setting will be inherited by all ISVNClient and ISVNRemote
+ * objects. Changing the setting will not affect existing such
+ * objects.
+ * @throws ClientException
+ */
+ public static void enableNativeCredentialsStore()
+ throws ClientException
+ {
+ configLib.enableNativeCredentialsStore();
+ }
+
+ /**
+ * Disable storing authentication credentials in Subversion's
+ * standard credentials store in the configuration directory and
+ * system-specific secure locations. In this mode, the
+ * authentication (see {@link ISVNClient#setPrompt} and {@link
+ * remote.RemoteFactory#setPrompt}) will be called every time the
+ * underlying library needs access to the credentials.
+ * <p>
+ * This mode is intented to support client implementations that
+ * use their own credentials store.
+ * <p>
+ * The standard credentials store is enabled by default.
+ * <p>
+ * This setting will be inherited by all ISVNClient and ISVNRemote
+ * objects. Changing the setting will not affect existing such
+ * objects.
+ * @throws ClientException
+ */
+ public static void disableNativeCredentialsStore()
+ throws ClientException
+ {
+ configLib.disableNativeCredentialsStore();
+ }
+
+ /**
+ * Find out if the standard credentials store is enabled.
+ */
+ public static boolean isNativeCredentialsStoreEnabled()
+ throws ClientException
+ {
+ return configLib.isNativeCredentialsStoreEnabled();
+ }
+
+ //
+ // Credentials management
+ //
+
+ /**
+ * Exception used by calling the wrong accessor on Credential for
+ * the given credential type.
+ */
+ public static class CredentialTypeMismatch extends SubversionException
+ {
+ // Update the serialVersionUID when there is a incompatible change made to
+ // this class. See the java documentation for when a change is incompatible.
+ // http://java.sun.com/javase/7/docs/platform/serialization/spec/version.html#6678
+ private static final long serialVersionUID = 1L;
+
+ public CredentialTypeMismatch(Credential.Kind kind, String attribute)
+ {
+ super("Credential type '" + kind.toString()
+ + "' does not have the attribute '" + attribute + "'");
+ }
+ }
+
+ /**
+ * Generic credential description. Provides default accessors for
+ * concrete implementations.
+ */
+ public static class Credential implements java.io.Serializable
+ {
+ // Update the serialVersionUID when there is a incompatible change made to
+ // this class. See the java documentation for when a change is incompatible.
+ // http://java.sun.com/javase/7/docs/platform/serialization/spec/version.html#6678
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Describes the kind of the credential.
+ */
+ public static enum Kind
+ {
+ /** The username for a realm. */
+ username ("svn.username"),
+
+ /** The username and password for a realm. */
+ simple ("svn.simple"),
+
+ /** The trusted SSL server certificate for a realm. */
+ sslServer ("svn.ssl.server"),
+
+ /** The client certificate passphrase for a realm. */
+ sslClientPassphrase ("svn.ssl.client-passphrase");
+
+ private String token;
+
+ Kind(String token)
+ {
+ this.token = token;
+ }
+
+ /** @return the string representation of the enumeration. */
+ public String toString()
+ {
+ return this.token;
+ }
+
+ /* Factory used by the native implementation */
+ private static Kind fromString(String stringrep)
+ {
+ for (Kind kind : Kind.values()) {
+ if (kind.toString().equals(stringrep))
+ return kind;
+ }
+ return null;
+ }
+ }
+
+ /** @return the kind of the credential. */
+ public Kind getKind()
+ {
+ return kind;
+ }
+
+ /** @return the realm that the credential is valid for. */
+ public String getRealm()
+ {
+ return realm;
+ }
+
+ /**
+ * @return the type of the secure store used for the secret
+ * parts of this credential; may be <code>null</code> if the
+ * credential does not contain any secrets bits.
+ */
+ public String getSecureStore()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.simple && kind != Kind.sslClientPassphrase)
+ throw new CredentialTypeMismatch(kind, "secure store");
+
+ return store;
+ }
+
+ /**
+ * @return the username associated with the credential, or
+ * <code>null</code>, if there is no username in the concrete
+ * credential type.
+ */
+ public String getUsername()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.username && kind != Kind.simple)
+ throw new CredentialTypeMismatch(kind, "username");
+
+ return username;
+ }
+
+ /**
+ * @return the password associated with the credential, or
+ * <code>null</code>, if there is no password in the concrete
+ * credential type.
+ */
+ public String getPassword()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.simple && kind != Kind.sslClientPassphrase)
+ throw new CredentialTypeMismatch(kind, "password");
+
+ return password;
+ }
+
+ /**
+ * @return the server certificate info associated with the
+ * credential, or <code>null</code>, if there is no server
+ * certificate in the concrete credential type.
+ */
+ public AuthnCallback.SSLServerCertInfo getServerCertInfo()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.sslServer)
+ throw new CredentialTypeMismatch(kind, "server cert info");
+
+ return info;
+ }
+
+ /**
+ * @return the accepted server certificate failures associated
+ * with the credential, or <code>null</code>, if there is no
+ * server certificate in the concrete credential type.
+ */
+ public AuthnCallback.SSLServerCertFailures getServerCertFailures()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.sslServer)
+ throw new CredentialTypeMismatch(kind, "server cert failures");
+
+ return failures;
+ }
+
+ /**
+ * @return the client certificate passphrase associated with
+ * the credential, or <code>null</code>, if there is no client
+ * certificate in the concrete credential type.
+ */
+ public String getClientCertPassphrase()
+ throws CredentialTypeMismatch
+ {
+ if (kind != Kind.sslClientPassphrase)
+ throw new CredentialTypeMismatch(kind, "passphrase");
+
+ return passphrase;
+ }
+
+ // ### TODO: There are currently no proper APIs in Subversion
+ // for adding credentials. These factory methods are
+ // placeholders.
+ //
+ ///**
+ // * Creates an "svn.username" credential.
+ // * @param realm The realm string.
+ // * @param username The username for <code>realm</code>.
+ // */
+ //public static Credential
+ // createUsername(String realm, String username)
+ //{
+ // return new Credential(Kind.username, realm, null,
+ // username, null, null, null, null);
+ //}
+ //
+ ///**
+ // * Creates an "svn.simple" credential.
+ // * @param realm The realm string.
+ // * @param username The username for <code>realm</code>.
+ // * @param password The password for <code>username</code>.
+ // */
+ //public static Credential
+ // createSimple(String realm, String username, String password)
+ //{
+ // return new Credential(Kind.simple, realm, null,
+ // username, password, null, null, null);
+ //}
+ //
+ ///** Creates an "svn.ssl.server" credential. */
+ //public static Credential
+ // createSSLServerCertTrust(String realm,
+ // AuthnCallback.SSLServerCertInfo info,
+ // AuthnCallback.SSLServerCertFailures failures)
+ //{
+ // return new Credential(Kind.sslServer, realm, null,
+ // null, null, info, failures, null);
+ //}
+ //
+ ///**
+ // * Creates an "svn.ssl.client-passphrase" credential.
+ // * @param realm The realm string.
+ // * @param passphrase The passphrase for for the client certificate
+ // * used for <code>realm</code>.
+ // */
+ //public static Credential
+ // createSSLClientCertPassphrase(String realm, String passphrase)
+ //{
+ // return new Credential(Kind.simple, realm, null,
+ // null, null, null, null, passphrase);
+ //}
+
+ private Credential(Kind kind, String realm, String store,
+ String username, String password,
+ AuthnCallback.SSLServerCertInfo info,
+ AuthnCallback.SSLServerCertFailures failures,
+ String passphrase)
+ {
+ assert(kind != null && realm != null);
+ switch (kind) {
+ case username:
+ assert(username != null && password == null
+ && info == null && failures == null
+ && passphrase == null);
+ break;
+ case simple:
+ assert(username != null && password != null
+ && info == null && failures == null
+ && passphrase == null);
+ break;
+ case sslServer:
+ assert(username == null && password == null
+ && info != null && failures != null
+ && passphrase == null);
+ break;
+ case sslClientPassphrase:
+ assert(username == null && password == null
+ && info == null && failures == null
+ && passphrase != null);
+ break;
+ default:
+ assert(kind == Kind.username
+ || kind == Kind.simple
+ || kind == Kind.sslServer
+ || kind == Kind.sslClientPassphrase);
+ }
+
+ this.kind = kind;
+ this.realm = realm;
+ this.store = store;
+ this.username = username;
+ this.password = password;
+ this.info = info;
+ this.failures = failures;
+ this.passphrase = passphrase;
+ }
+
+ private Kind kind;
+ private String realm;
+ private String store;
+ private String username;
+ private String password;
+ private AuthnCallback.SSLServerCertInfo info;
+ private AuthnCallback.SSLServerCertFailures failures;
+ private String passphrase;
+ }
+
+ /**
+ * Find a stored credential.
+ * Unlike {@link #searchCredentials}, the the realm name is not
+ * a glob pattern.
+ * <p>
+ * <b>Note:</b> If the native credentials store is disabled, this
+ * method will always return <code>null</code>.
+ *
+ * @param configDir The path to the configuration directory; if
+ * <code>null</code>, the default (system-specific) user
+ * configuration path will be used.
+ * @param kind The kind of the credential; may not be <code>null</code>.
+ * @param realm The realm name; may not be <code>null</code>.
+ * @return the matching credential, or <code>null</code> if not found.
+ */
+ public static Credential getCredential(String configDir,
+ Credential.Kind kind,
+ String realm)
+ throws ClientException, SubversionException
+ {
+ return configLib.getCredential(configDir, kind, realm);
+ }
+
+ /**
+ * Remove a stored credential.
+ * Unlike {@link #deleteCredentials}, the the realm name is not
+ * a glob pattern.
+ * <p>
+ * <b>Note:</b> If the native credentials store is disabled, this
+ * method will always return <code>null</code>.
+ *
+ * @param configDir The path to the configuration directory; if
+ * <code>null</code>, the default (system-specific) user
+ * configuration path will be used.
+ * @param kind The kind of the credential; may not be <code>null</code>.
+ * @param realm The realm name; may not be <code>null</code>.
+ * @return the deleted credential, or <code>null</code> if not found.
+ */
+ public static Credential removeCredential(String configDir,
+ Credential.Kind kind,
+ String realm)
+ throws ClientException, SubversionException
+ {
+ return configLib.removeCredential(configDir, kind, realm);
+ }
+
+ // ### TODO: There are currently no proper APIs in Subversion for
+ // adding credentials. This method is a placeholder.
+ //
+ ///**
+ // * Store a new credential, or replace an existing credential.
+ // * <p>
+ // * <b>Note:</b> If the native credentials store is disabled, this
+ // * method will always return <code>null</code>.
+ // *
+ // * @param configDir The path to the configuration directory; if
+ // * <code>null</code>, the default (system-specific) user
+ // * configuration path will be used.
+ // * @param credential The credential to store.
+ // * @param replace If <code>true</code>, any existing matching
+ // * credential will be replaced.
+ // *
+ // * @return the stored credential. If <code>replace</code> was
+ // * <code>false</code>, and a credential with the same kind and
+ // * for the same realm exists, it will be returned. If the given
+ // * credential was successfully added, the same object reference
+ // * will be returned (the calling code can compare reference values
+ // * to determine this). Will return <code>null</code> if the
+ // * credential could not be stored for any reason.
+ // */
+ //public static Credential addCredential(String configDir,
+ // Credential credential,
+ // boolean replace)
+ // throws ClientException, SubversionException
+ //{
+ // return configLib.addCredential(configDir, credential, replace);
+ //}
+
+ /**
+ * Find stored credentials that match the given search criteria.
+ * <p>
+ * <b>Note:</b> If the native credentials store is disabled, this
+ * method will always return <code>null</code>.
+ *
+ * @param configDir The path to the configuration directory; if
+ * <code>null</code>, the default (system-specific) user
+ * configuration path will be used.
+ * @param kind The kind of the credential; if <code>null</code>,
+ * all matching credential types will be returned.
+ * @param realmPattern A glob pattern for the realm string;
+ * if <code>null</code>, all realms will be considered;
+ * otherwise, only those credentials whose realm matches
+ * the pattern will be returned.
+ * @param usernamePattern A glob pattern for the username;
+ * if <code>null</code>, all credentials will be considered;
+ * otherwise, only those credentials that have a username,
+ * and where the username matches the pattern, will be
+ * returned.
+ * @param hostnamePattern A glob pattern for the hostnames of a
+ * server certificate; if <code>null</code>, all
+ * credntials will be considered; otherwise, only
+ * those credentials that have a server certificate
+ * with a hostname that matches the pattern will be
+ * returned.
+ * @param textPattern A glob pattern that must match any textual
+ * information in a credential, for example, a realm,
+ * username, certificate details, etc; passwords, passphrases
+ * and other info considered secret will not be matched;
+ * @return the list of matching credentials.
+ */
+ public static List<Credential>
+ searchCredentials(String configDir,
+ Credential.Kind kind,
+ String realmPattern,
+ String usernamePattern,
+ String hostnamePattern,
+ String textPattern)
+ throws ClientException, SubversionException
+ {
+ return configLib.searchCredentials(configDir, kind, realmPattern,
+ usernamePattern, hostnamePattern,
+ textPattern);
+ }
+
+ //
+ // Diff and Merge
+ //
+ private static final DiffLib diffLib = new DiffLib();
+
+ /**
+ * Options to control the behaviour of the file diff routines.
+ */
+ public static class DiffOptions
+ {
+ /**
+ * To what extent whitespace should be ignored when comparing lines.
+ */
+ public enum IgnoreSpace
+ {
+ /** Do not ignore whitespace */
+ none,
+
+ /**
+ * Ignore changes in sequences of whitespace characters,
+ * treating each sequence of whitespace characters as a
+ * single space.
+ */
+ change,
+
+ /** Ignore all whitespace characters. */
+ all
+ }
+
+ /**
+ * @param ignoreSpace Whether and how to ignore space differences
+ * in the files. The default is {@link IgnoreSpace#none}.
+ * @param ignoreEolStyle Whether to treat all end-of-line
+ * markers the same when comparing lines. The default
+ * is <code>false</code>.
+ * @param showCFunction Whether the "@@" lines of the unified
+ * diff output should include a prefix of the nearest
+ * preceding line that starts with a character that
+ * might be the initial character of a C language
+ * identifier. The default is <code>false</code>.
+ */
+ public DiffOptions(IgnoreSpace ignoreSpace,
+ boolean ignoreEolStyle,
+ boolean showCFunction)
+ {
+ this.ignoreSpace = ignoreSpace;
+ this.ignoreEolStyle = ignoreEolStyle;
+ this.showCFunction = showCFunction;
+ this.contextSize = -1;
+ }
+
+ /**
+ * Like the {@see #DiffOptions(IgnoreSpace,boolean,boolean)},
+ * but with an additional parameter.
+ * @param contextSize If this is greater than 0, then this
+ * number of context lines will be used in the generated diff
+ * output. Otherwise the legacy compile time default will be
+ * used.
+ */
+ public DiffOptions(IgnoreSpace ignoreSpace,
+ boolean ignoreEolStyle,
+ boolean showCFunction,
+ int contextSize)
+ {
+ this.ignoreSpace = ignoreSpace;
+ this.ignoreEolStyle = ignoreEolStyle;
+ this.showCFunction = showCFunction;
+ this.contextSize = contextSize;
+ }
+
+ public final IgnoreSpace ignoreSpace;
+ public final boolean ignoreEolStyle;
+ public final boolean showCFunction;
+ public final int contextSize;
+ }
+
+ /** Style for displaying conflicts in merge output. */
+ public enum ConflictDisplayStyle
+ {
+ /** Display modified and latest, with conflict markers. */
+ modified_latest,
+
+ /**
+ * Like <code>modified_latest</code>, but with an extra effort
+ * to identify common sequences between modified and latest.
+ */
+ resolved_modified_latest,
+
+ /** Display modified, original, and latest, with conflict markers. */
+ modified_original_latest,
+
+ /** Just display modified, with no markers. */
+ modified,
+
+ /** Just display latest, with no markers. */
+ latest,
+
+ /**
+ * Like <code>modified_original_latest</code>, but
+ * <em>only<em> showing conflicts.
+ */
+ only_conflicts
+ }
+
+ /**
+ * Given two versions of a file, base (<code>originalFile</code>)
+ * and current (<code>modifiedFile</code>), show differences between
+ * them in unified diff format.
+ *
+ * @param originalFile The base file version (unmodified)
+ * @param modifiedFile The incoming file version (locally modified)
+ * @param diffOptions Options controlling how files are compared.
+ * May be <code>null</code>.
+ * @param originalHeader The header to display for the base file
+ * in the unidiff index block. If it is <code>null</code>,
+ * the <code>originalFile</code> path and its modification
+ * time will be used instead.
+ * @param modifiedHeader The header to display for the current
+ * file in the unidiff index block. If it is <code>null</code>,
+ * the <code>currentFile</code> path and its modification
+ * time will be used instead.
+ * @param headerEncoding The character encoding of the unidiff headers.
+ * @param relativeToDir If this parameter is not <null>, it must
+ * be the path of a (possibly non-immediate) parent of both
+ * <code>originalFile</code> and <code>modifiedFile</code>.
+ * This path will be stripped from the beginning of those
+ * file names if they are used in the unidiff index header.
+ * @param resultStream The stream that receives the merged output.
+ * @return <code>true</code> if there were differences between the files.
+ * @throws ClientException
+ */
+ public static boolean fileDiff(String originalFile,
+ String modifiedFile,
+ SVNUtil.DiffOptions diffOptions,
+
+ String originalHeader,
+ String modifiedHeader,
+ String headerEncoding,
+ String relativeToDir,
+
+ OutputStream resultStream)
+ throws ClientException
+ {
+ // ### TODO: Support cancellation as in svn_diff_file_output_unified3.
+ return diffLib.fileDiff(originalFile, modifiedFile, diffOptions,
+ originalHeader, modifiedHeader,
+ headerEncoding,
+ relativeToDir, resultStream);
+ }
+
+
+ /**
+ * Given three versions of a file, base (<code>originalFile</code>),
+ * incoming (<code>modifiedFile</code>) and current
+ * (<code>latestFile</code>, produce a merged result, possibly
+ * displaying conflict markers.
+ *
+ * @param originalFile The base file version (common ancestor)
+ * @param modifiedFile The incoming file version (modified elsewhere)
+ * @param latestFile The current file version (locally modified)
+ * @param diffOptions Options controlling how files are compared.
+ * May be <code>null</code>.
+ * @param conflictOriginal Optional custom conflict marker for
+ * the <code>originalFile</code> contents.
+ * @param conflictModified Optional custom conflict marker for
+ * the <code>modifiedFile</code> contents.
+ * @param conflictLatest Optional custom conflict marker for
+ * the <code>latestFile</code> contents.
+ * @param conflictSeparator Optional custom conflict separator.
+ * @param conflictStyle Determines how conflicts are displayed.
+ * @param resultStream The stream that receives the merged output.
+ * @return <code>true</code> if there were any conflicts.
+ * @throws ClientException
+ */
+ public static boolean fileMerge(String originalFile,
+ String modifiedFile,
+ String latestFile,
+ DiffOptions diffOptions,
+
+ String conflictOriginal,
+ String conflictModified,
+ String conflictLatest,
+ String conflictSeparator,
+ ConflictDisplayStyle conflictStyle,
+
+ OutputStream resultStream)
+ throws ClientException
+ {
+ return diffLib.fileMerge(originalFile, modifiedFile, latestFile,
+ diffOptions,
+ conflictOriginal, conflictModified,
+ conflictLatest, conflictSeparator,
+ conflictStyle, resultStream);
+ }
+
+ //
+ // Property validation and parsing
+ //
+ private static final PropLib propLib = new PropLib();
+
+ /**
+ * Validate the value of an <code>svn:</code> property on file or
+ * directory and return a canonical representation of its value.
+ * @param name The name of the property (must be a valid svn: property)
+ * @param value The property's value
+ * @param path The path or URL of the file or directory that
+ * owns the property; only used for error messages
+ * @param kind The node kind of the file or dir that owns the property
+ * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
+ * tye file's mime-type, used for extra validation for the
+ * <code>svn:eol-style</code> property. If it is <code>null</code>,
+ * the extra validation will be skipped.
+ * @return a canonicalized representation of the property value
+ * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
+ */
+ public static byte[] canonicalizeNodeProperty(
+ String name, byte[] value, String path, NodeKind kind,
+ String mimeType)
+ throws ClientException
+ {
+ return propLib.canonicalizeNodeProperty(
+ name, value, path, kind, mimeType, null);
+ }
+
+ /**
+ * Validate the value of an <code>svn:</code> property on file or
+ * directory and return a canonical representation of its value.
+ * @param name The name of the property (must be a valid svn: property)
+ * @param value The property's value
+ * @param path The path or URL of the file or directory that
+ * owns the property; only used for error messages
+ * @param kind The node kind of the file or dir that owns the property
+ * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
+ * tye file's mime-type, used for extra validation for the
+ * <code>svn:eol-style</code> property. If it is <code>null</code>,
+ * the extra validation will be skipped.
+ * @param fileContents A stream with the file's contents. Only used
+ * to check for line-ending consistency when validating the
+ * <code>svn:eol-style</code> property, and only when
+ * <code>kind</code> is {@link NodeKind.file} and
+ * <code>mimeType</code> is not <code>null</code>.
+ * @return a canonicalized representation of the property value
+ * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
+ */
+ public static byte[] canonicalizeNodeProperty(
+ String name, byte[] value, String path, NodeKind kind,
+ String mimeType, InputStream fileContents)
+ throws ClientException
+ {
+ return propLib.canonicalizeNodeProperty(
+ name, value, path, kind, mimeType, fileContents);
+ }
+
+ /**
+ * Parse <code>description</code>, assuming it is an externals
+ * specification in the format required for the
+ * <code>svn:externals</code> property, and return a list of
+ * parsed external items.
+ * @param description The externals description.
+ * @param parentDirectory Used to construct error messages.
+ * @param canonicalizeUrl Whe <code>true</code>, canonicalize the
+ * <code>url</code> member of the returned objects. If the
+ * <code>url</code> member refers to an absolute URL, it will
+ * be canonicalized as URL consistent with the way URLs are
+ * canonicalized throughout the Subversion API. If, however,
+ * the <code>url</code> member makes use of the recognized
+ * (SVN-specific) relative URL syntax for
+ * <code>svn:externals</code>, "canonicalization" is an
+ * ill-defined concept which may even result in munging the
+ * relative URL syntax beyond recognition. You've been warned.
+ * @return a list of {@link ExternalItem}s
+ */
+ public static List<ExternalItem> parseExternals(byte[] description,
+ String parentDirectory,
+ boolean canonicalizeUrl)
+ throws ClientException
+ {
+ return propLib.parseExternals(description, parentDirectory,
+ canonicalizeUrl);
+ }
+
+ /**
+ * Unparse and list of external items into a format suitable for
+ * the value of the <code>svn:externals</code> property and
+ * validate the result.
+ * @param items The list of {@link ExternalItem}s
+ * @param parentDirectory Used to construct error messages.
+ * @param compatibleWithSvn1_5 When <code>true</code>, the format
+ * of the returned property value will be compatible with
+ * clients older than Subversion 1.5.
+ */
+ public static byte[] unparseExternals(List<ExternalItem> items,
+ String parentDirectory)
+ throws SubversionException
+ {
+ return propLib.unparseExternals(items, parentDirectory, false);
+ }
+
+ /**
+ * Unparse and list of external items into a format suitable for
+ * the value of the <code>svn:externals</code> property compatible
+ * with Subversion clients older than release 1.5, and validate
+ * the result.
+ * @param items The list of {@link ExternalItem}s
+ * @param parentDirectory Used to construct error messages.
+ */
+ public static byte[] unparseExternalsForAncientUnsupportedClients(
+ List<ExternalItem> items, String parentDirectory)
+ throws SubversionException
+ {
+ return propLib.unparseExternals(items, parentDirectory, true);
+ }
+
+ /**
+ * If the URL in <code>external</code> is relative, resolve it to
+ * an absolute URL, using <code>reposRootUrl</code> and
+ * <code>parentDirUrl</code> to provide contest.
+ *<p>
+ * Regardless if the URL is absolute or not, if there are no
+ * errors, the returned URL will be canonicalized.
+ *<p>
+ * The following relative URL formats are supported:
+ * <dl>
+ * <dt><code>../</code></dt>
+ * <dd>relative to the parent directory of the external</dd>
+ * <dt><code>^/</code></dt>
+ * <dd>relative to the repository root</dd>
+ * <dt><code>//</code></dt>
+ * <dd>relative to the scheme</dd>
+ * <dt><code>/</code></dt>
+ * <dd>relative to the server's hostname</dd>
+ * </dl>
+ *<p>
+ * The <code>../<code> and ^/ relative URLs may use <code>..</code>
+ * to remove path elements up to the server root.
+ *<p>
+ * The external URL should not be canonicalized before calling
+ * this function, as otherwise the scheme relative URL
+ * '<code>//host/some/path</code>' would have been canonicalized
+ * to '<code>/host/some/path</code>' and we would not be able to
+ * match on the leading '<code>//</code>'.
+ */
+ public static String resolveExternalsUrl(ExternalItem external,
+ String reposRootUrl,
+ String parentDirUrl)
+ throws ClientException
+ {
+ return propLib.resolveExternalsUrl(
+ external, reposRootUrl, parentDirUrl);
+ }
+
+ //
+ // Newline translation and keyword expansion
+ //
+ private static final SubstLib substLib = new SubstLib();
+
+ /**
+ * Use the linefeed code point ('<code>\x0a</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_LF = SubstLib.EOL_LF;
+
+ /**
+ * Use the carraige-return code point ('<code>\x0d</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_CR = SubstLib.EOL_CR;
+
+ /**
+ * Use carriage-return/linefeed sequence ('<code>\x0d\x0a</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_CRLF = SubstLib.EOL_CRLF;
+
+
+ /**
+ * Build a dictionary of expanded keyword values, given the
+ * contents of a file's <code>svn:keywords</code> property, its
+ * revision, URL, the date it was committed on, the author of the
+ * commit and teh URL of the repository root.
+ *<p>
+ * Custom keywords defined in <code>svn:keywords</code> properties
+ * are expanded using the provided parameters and in accordance
+ * with the following format substitutions in the
+ * <code>keywordsValue</code>:
+ * <dl>
+ * <dt><code>%a</dt></code>
+ * <dd>The author.</dd>
+ * <dt><code>%b</dt></code>
+ * <dd>The basename of the URL.</dd>
+ * <dt><code>%d</dt></code>
+ * <dd>Short format of the date.</dd>
+ * <dt><code>%D</dt></code>
+ * <dd>Long format of the date.</dd>
+ * <dt><code>%P</dt></code>
+ * <dd>The file's path, relative to the repository root URL.</dd>
+ * <dt><code>%r</dt></code>
+ * <dd>The revision.</dd>
+ * <dt><code>%R</dt></code>
+ * <dd>The URL to the root of the repository.</dd>
+ * <dt><code>%u</dt></code>
+ * <dd>The URL of the file.</dd>
+ * <dt><code>%_</dt></code>
+ * <dd>A space (keyword definitions cannot contain a literal space).</dd>
+ * <dt><code>%%</dt></code>
+ * <dd>A literal '%'.</dd>
+ * <dt><code>%H</dt></code>
+ * <dd>Equivalent to <code>%P%_%r%_%d%_%a</code>.</dd>
+ * <dt><code>%I</dt></code>
+ * <dd>Equivalent to <code>%b%_%r%_%d%_%a</code>.</dd>
+ * </dl>
+ *<p>
+ * Custom keywords are defined by appending '=' to the keyword
+ * name, followed by a string containing any combination of the
+ * format substitutions.
+ *<p>
+ * Any of the <code>revision</code>, <code>url</code>,
+ * <code>reposRootUrl</code>, <code>date</code> and
+ * <code>author</code> parameters may be <code>null</code>, or
+ * {@link Revision#SVN_INVALID_REVNUM} for <code>revision</code>,
+ * to indicate that the information is not present. Each piece of
+ * information that is not present expands to the empty string
+ * wherever it appears in an expanded keyword value. (This can
+ * result in multiple adjacent spaces in the expansion of a
+ * multi-valued keyword such as "<code>Id</code>".)
+ */
+ public static Map<String, byte[]> buildKeywords(byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.buildKeywords(keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
+
+ /**
+ * Return a stream which performs end-of-line translation and
+ * keyword expansion when read from.
+ *<p>
+ * <b>Important:</b> Make sure you close the returned stream to
+ * ensure all data are flushed and cleaned up (this will also
+ * close the provided stream and dispose the related netive
+ * object).
+ *<p>
+ * If <code>eolMarker</code> is not <code>null</code>, replace
+ * whatever any end-of-line sequences in the input with
+ * <code>eolMarker</code>. If the input has an inconsistent line
+ * ending style, then:
+ * <ul>
+ * <li>if <code>repairEol</code> is <code>false</code>, then a
+ * subsequent read or other operation on the stream will
+ * generate an error when the inconsistency is detected;</li>
+ * <li>if <code>repaorEol</code> is <code>true</code>, convert any
+ * line ending to <code>eolMarker</code>.<br/>
+ * Recognized line endings are: "<code>\n</code>",
+ * "<code>\r</code>", and "<code>\r\n</code>".</li>
+ * </ul>
+ *<p>
+ * Expand or contract keywords using the contents of
+ * <code>keywords</code> as the new values. If
+ * <code>expandKeywords</code> is <code>true</code>, expand
+ * contracted keywords and re-expand expanded keywords; otherwise,
+ * contract expanded keywords and ignore contracted ones.
+ * Keywords not found in the dictionary are ignored (not
+ * contracted or expanded). If the <code>keywords</code> itself
+ * is <code>null</code>, keyword substitution will be altogether
+ * ignored.
+ *<p>
+ * Detect only keywords that are no longer than
+ * <code>SVN_KEYWORD_MAX_LEN</code> bytes (currently: 255),
+ * including the delimiters and the keyword itself.
+ *<p>
+ * Recommendation: if <code>expandKeywords</code> is
+ * <code>false</code>, then you don't care about the keyword
+ * values, so just put <code>null</code> values into the
+ * <code>keywords</code> dictionary.
+ *<p>
+ * If the inner stream implements marking and seeking via
+ * {@link InputStream#mark} and {@link InputStream#reset}, the
+ * translated stream will too.
+ *
+ * @param source the source (untranslated) stream.
+ * @param eolMarker the byte sequence to use as the end-of-line marker;
+ * must be one of {@link #EOL_LF}, {@link #EOL_CR}
+ * or {@link #EOL_CRLF}.
+ * @param repairEol flag to repair end-of-lines; see above
+ * @param keywords the keyword dictionary; see {@link buildKeywords}
+ * @param expandKeywords flag to expand keywords
+ */
+ public static InputStream translateStream(InputStream source,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean expandKeywords)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateInputStream(
+ source, eolMarker, repairEol,
+ keywords, true, expandKeywords,
+ null, Revision.SVN_INVALID_REVNUM,
+ null, null, null, null);
+ }
+
+ /**
+ * Expand keywords and return a stream which performs end-of-line
+ * translation and keyword expansion when read from.
+ * @see buildKeywords
+ * @see translateStream(InputStream,byte[],boolean,Map,boolean)
+ */
+ public static InputStream translateStream(InputStream source,
+ byte[] eolMarker,
+ boolean repairEol,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateInputStream(
+ source, eolMarker, repairEol,
+ null, false, expandKeywords,
+ keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
+
+ /**
+ * Return a stream which performs end-of-line translation and
+ * keyword expansion when written to. Behaves like
+ * {@link #translateStream(InputStream,byte[],boolean,Map,boolean)},
+ * except that it translates an <code>OutputStream</code> and never
+ * supports marking and seeking.
+ */
+ public static OutputStream translateStream(OutputStream destination,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean expandKeywords)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateOutputStream(
+ destination, eolMarker, repairEol,
+ keywords, true, expandKeywords,
+ null, Revision.SVN_INVALID_REVNUM,
+ null, null, null, null);
+ }
+
+ /**
+ * Expand keywords and return a stream which performs end-of-line
+ * translation and keyword expansion when written to.
+ * @see buildKeywords
+ * @see translateStream(OutputStream,byte[],boolean,Map,boolean)
+ */
+ public static OutputStream translateStream(OutputStream destination,
+ byte[] eolMarker,
+ boolean repairEol,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateOutputStream(
+ destination, eolMarker, repairEol,
+ null, false, expandKeywords,
+ keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
+}