~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @copyright
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 * @endcopyright
 
22
 */
 
23
 
 
24
package org.apache.subversion.javahl;
 
25
 
 
26
import org.apache.subversion.javahl.callback.*;
 
27
import org.apache.subversion.javahl.types.*;
 
28
import org.apache.subversion.javahl.util.*;
 
29
 
 
30
import java.io.InputStream;
 
31
import java.io.OutputStream;
 
32
import java.util.Date;
 
33
import java.util.List;
 
34
import java.util.Map;
 
35
 
 
36
public class SVNUtil
 
37
{
 
38
    //
 
39
    // Global configuration
 
40
    //
 
41
    private static final ConfigLib configLib = new ConfigLib();
 
42
 
 
43
    /**
 
44
     * Enable storing authentication credentials in Subversion's
 
45
     * standard credentials store in the configuration directory and
 
46
     * system-specific secure locations.
 
47
     * <p>
 
48
     * The standard credentials store is enabled by default.
 
49
     * <p>
 
50
     * This setting will be inherited by all ISVNClient and ISVNRemote
 
51
     * objects. Changing the setting will not affect existing such
 
52
     * objects.
 
53
     * @throws ClientException
 
54
     */
 
55
    public static void enableNativeCredentialsStore()
 
56
        throws ClientException
 
57
      {
 
58
          configLib.enableNativeCredentialsStore();
 
59
      }
 
60
 
 
61
    /**
 
62
     * Disable storing authentication credentials in Subversion's
 
63
     * standard credentials store in the configuration directory and
 
64
     * system-specific secure locations. In this mode, the
 
65
     * authentication (see {@link ISVNClient#setPrompt} and {@link
 
66
     * remote.RemoteFactory#setPrompt}) will be called every time the
 
67
     * underlying library needs access to the credentials.
 
68
     * <p>
 
69
     * This mode is intented to support client implementations that
 
70
     * use their own credentials store.
 
71
     * <p>
 
72
     * The standard credentials store is enabled by default.
 
73
     * <p>
 
74
     * This setting will be inherited by all ISVNClient and ISVNRemote
 
75
     * objects. Changing the setting will not affect existing such
 
76
     * objects.
 
77
     * @throws ClientException
 
78
     */
 
79
    public static void disableNativeCredentialsStore()
 
80
        throws ClientException
 
81
      {
 
82
          configLib.disableNativeCredentialsStore();
 
83
      }
 
84
 
 
85
    /**
 
86
     * Find out if the standard credentials store is enabled.
 
87
     */
 
88
    public static boolean isNativeCredentialsStoreEnabled()
 
89
        throws ClientException
 
90
      {
 
91
          return configLib.isNativeCredentialsStoreEnabled();
 
92
      }
 
93
 
 
94
    //
 
95
    // Credentials management
 
96
    //
 
97
 
 
98
    /**
 
99
     * Exception used by calling the wrong accessor on Credential for
 
100
     * the given credential type.
 
101
     */
 
102
    public static class CredentialTypeMismatch extends SubversionException
 
103
    {
 
104
        // Update the serialVersionUID when there is a incompatible change made to
 
105
        // this class.  See the java documentation for when a change is incompatible.
 
106
        // http://java.sun.com/javase/7/docs/platform/serialization/spec/version.html#6678
 
107
        private static final long serialVersionUID = 1L;
 
108
 
 
109
        public CredentialTypeMismatch(Credential.Kind kind, String attribute)
 
110
        {
 
111
            super("Credential type '" + kind.toString()
 
112
                  + "'  does not have the attribute '" + attribute + "'");
 
113
        }
 
114
    }
 
115
 
 
116
    /**
 
117
     * Generic credential description. Provides default accessors for
 
118
     * concrete implementations.
 
119
     */
 
120
    public static class Credential implements java.io.Serializable
 
121
    {
 
122
        // Update the serialVersionUID when there is a incompatible change made to
 
123
        // this class.  See the java documentation for when a change is incompatible.
 
124
        // http://java.sun.com/javase/7/docs/platform/serialization/spec/version.html#6678
 
125
        private static final long serialVersionUID = 1L;
 
126
 
 
127
        /**
 
128
         * Describes the kind of the credential.
 
129
         */
 
130
        public static enum Kind
 
131
        {
 
132
            /** The username for a realm. */
 
133
            username            ("svn.username"),
 
134
 
 
135
            /** The username and password for a realm. */
 
136
            simple              ("svn.simple"),
 
137
 
 
138
            /** The trusted SSL server certificate for a realm. */
 
139
            sslServer           ("svn.ssl.server"),
 
140
 
 
141
            /** The client certificate passphrase for a realm. */
 
142
            sslClientPassphrase ("svn.ssl.client-passphrase");
 
143
 
 
144
            private String token;
 
145
 
 
146
            Kind(String token)
 
147
            {
 
148
                this.token = token;
 
149
            }
 
150
 
 
151
            /** @return the string representation of the enumeration. */
 
152
            public String toString()
 
153
            {
 
154
                return this.token;
 
155
            }
 
156
 
 
157
            /* Factory used by the native implementation */
 
158
            private static Kind fromString(String stringrep)
 
159
            {
 
160
                for (Kind kind : Kind.values()) {
 
161
                    if (kind.toString().equals(stringrep))
 
162
                        return kind;
 
163
                }
 
164
                return null;
 
165
            }
 
166
        }
 
167
 
 
168
        /** @return the kind of the credential. */
 
169
        public Kind getKind()
 
170
        {
 
171
            return kind;
 
172
        }
 
173
 
 
174
        /** @return the realm that the credential is valid for. */
 
175
        public String getRealm()
 
176
        {
 
177
            return realm;
 
178
        }
 
179
 
 
180
        /**
 
181
         * @return the type of the secure store used for the secret
 
182
         * parts of this credential; may be <code>null</code> if the
 
183
         * credential does not contain any secrets bits.
 
184
         */
 
185
        public String getSecureStore()
 
186
            throws CredentialTypeMismatch
 
187
        {
 
188
            if (kind != Kind.simple && kind != Kind.sslClientPassphrase)
 
189
                throw new CredentialTypeMismatch(kind, "secure store");
 
190
 
 
191
            return store;
 
192
        }
 
193
 
 
194
        /**
 
195
         * @return the username associated with the credential, or
 
196
         * <code>null</code>, if there is no username in the concrete
 
197
         * credential type.
 
198
         */
 
199
        public String getUsername()
 
200
            throws CredentialTypeMismatch
 
201
        {
 
202
            if (kind != Kind.username && kind != Kind.simple)
 
203
                throw new CredentialTypeMismatch(kind, "username");
 
204
 
 
205
            return username;
 
206
        }
 
207
 
 
208
        /**
 
209
         * @return the password associated with the credential, or
 
210
         * <code>null</code>, if there is no password in the concrete
 
211
         * credential type.
 
212
         */
 
213
        public String getPassword()
 
214
            throws CredentialTypeMismatch
 
215
        {
 
216
            if (kind != Kind.simple && kind != Kind.sslClientPassphrase)
 
217
                throw new CredentialTypeMismatch(kind, "password");
 
218
 
 
219
            return password;
 
220
        }
 
221
 
 
222
        /**
 
223
         * @return the server certificate info associated with the
 
224
         * credential, or <code>null</code>, if there is no server
 
225
         * certificate in the concrete credential type.
 
226
         */
 
227
        public AuthnCallback.SSLServerCertInfo getServerCertInfo()
 
228
            throws CredentialTypeMismatch
 
229
        {
 
230
            if (kind != Kind.sslServer)
 
231
                throw new CredentialTypeMismatch(kind, "server cert info");
 
232
 
 
233
            return info;
 
234
        }
 
235
 
 
236
        /**
 
237
         * @return the accepted server certificate failures associated
 
238
         * with the credential, or <code>null</code>, if there is no
 
239
         * server certificate in the concrete credential type.
 
240
         */
 
241
        public AuthnCallback.SSLServerCertFailures getServerCertFailures()
 
242
            throws CredentialTypeMismatch
 
243
        {
 
244
            if (kind != Kind.sslServer)
 
245
                throw new CredentialTypeMismatch(kind, "server cert failures");
 
246
 
 
247
            return failures;
 
248
        }
 
249
 
 
250
        /**
 
251
         * @return the client certificate passphrase associated with
 
252
         * the credential, or <code>null</code>, if there is no client
 
253
         * certificate in the concrete credential type.
 
254
         */
 
255
        public String getClientCertPassphrase()
 
256
            throws CredentialTypeMismatch
 
257
        {
 
258
            if (kind != Kind.sslClientPassphrase)
 
259
                throw new CredentialTypeMismatch(kind, "passphrase");
 
260
 
 
261
            return passphrase;
 
262
        }
 
263
 
 
264
        // ### TODO: There are currently no proper APIs in Subversion
 
265
        //           for adding credentials. These factory methods are
 
266
        //           placeholders.
 
267
        //
 
268
        ///**
 
269
        // * Creates an "svn.username" credential.
 
270
        // * @param realm The realm string.
 
271
        // * @param username The username for <code>realm</code>.
 
272
        // */
 
273
        //public static Credential
 
274
        //    createUsername(String realm, String username)
 
275
        //{
 
276
        //    return new Credential(Kind.username, realm, null,
 
277
        //                          username, null, null, null, null);
 
278
        //}
 
279
        //
 
280
        ///**
 
281
        // * Creates an "svn.simple" credential.
 
282
        // * @param realm The realm string.
 
283
        // * @param username The username for <code>realm</code>.
 
284
        // * @param password The password for <code>username</code>.
 
285
        // */
 
286
        //public static Credential
 
287
        //    createSimple(String realm, String username, String password)
 
288
        //{
 
289
        //    return new Credential(Kind.simple, realm, null,
 
290
        //                          username, password, null, null, null);
 
291
        //}
 
292
        //
 
293
        ///** Creates an "svn.ssl.server" credential. */
 
294
        //public static Credential
 
295
        //    createSSLServerCertTrust(String realm,
 
296
        //                             AuthnCallback.SSLServerCertInfo info,
 
297
        //                             AuthnCallback.SSLServerCertFailures failures)
 
298
        //{
 
299
        //    return new Credential(Kind.sslServer, realm, null,
 
300
        //                          null, null, info, failures, null);
 
301
        //}
 
302
        //
 
303
        ///**
 
304
        // * Creates an "svn.ssl.client-passphrase" credential.
 
305
        // * @param realm The realm string.
 
306
        // * @param passphrase The passphrase for for the client certificate
 
307
        // *        used for <code>realm</code>.
 
308
        // */
 
309
        //public static Credential
 
310
        //    createSSLClientCertPassphrase(String realm, String passphrase)
 
311
        //{
 
312
        //    return new Credential(Kind.simple, realm, null,
 
313
        //                          null, null, null, null, passphrase);
 
314
        //}
 
315
 
 
316
        private Credential(Kind kind, String realm, String store,
 
317
                           String username, String password,
 
318
                           AuthnCallback.SSLServerCertInfo info,
 
319
                           AuthnCallback.SSLServerCertFailures failures,
 
320
                           String passphrase)
 
321
        {
 
322
            assert(kind != null && realm != null);
 
323
            switch (kind) {
 
324
            case username:
 
325
                assert(username != null && password == null
 
326
                       && info == null && failures == null
 
327
                       && passphrase == null);
 
328
                break;
 
329
            case simple:
 
330
                assert(username != null && password != null
 
331
                       && info == null && failures == null
 
332
                       && passphrase == null);
 
333
                break;
 
334
            case sslServer:
 
335
                assert(username == null && password == null
 
336
                       && info != null && failures != null
 
337
                       && passphrase == null);
 
338
                break;
 
339
            case sslClientPassphrase:
 
340
                assert(username == null && password == null
 
341
                       && info == null && failures == null
 
342
                       && passphrase != null);
 
343
                break;
 
344
            default:
 
345
                assert(kind == Kind.username
 
346
                       || kind == Kind.simple
 
347
                       || kind == Kind.sslServer
 
348
                       || kind == Kind.sslClientPassphrase);
 
349
            }
 
350
 
 
351
            this.kind = kind;
 
352
            this.realm = realm;
 
353
            this.store = store;
 
354
            this.username = username;
 
355
            this.password = password;
 
356
            this.info = info;
 
357
            this.failures = failures;
 
358
            this.passphrase = passphrase;
 
359
        }
 
360
 
 
361
        private Kind kind;
 
362
        private String realm;
 
363
        private String store;
 
364
        private String username;
 
365
        private String password;
 
366
        private AuthnCallback.SSLServerCertInfo info;
 
367
        private AuthnCallback.SSLServerCertFailures failures;
 
368
        private String passphrase;
 
369
    }
 
370
 
 
371
    /**
 
372
     * Find a stored credential.
 
373
     * Unlike {@link #searchCredentials}, the the realm name is not
 
374
     * a glob pattern.
 
375
     * <p>
 
376
     * <b>Note:</b> If the native credentials store is disabled, this
 
377
     *              method will always return <code>null</code>.
 
378
     *
 
379
     * @param configDir The path to the configuration directory; if
 
380
     *        <code>null</code>, the default (system-specific) user
 
381
     *        configuration path will be used.
 
382
     * @param kind The kind of the credential; may not be <code>null</code>.
 
383
     * @param realm The realm name; may not be <code>null</code>.
 
384
     * @return the matching credential, or <code>null</code> if not found.
 
385
     */
 
386
    public static Credential getCredential(String configDir,
 
387
                                           Credential.Kind kind,
 
388
                                           String realm)
 
389
        throws ClientException, SubversionException
 
390
    {
 
391
        return configLib.getCredential(configDir, kind, realm);
 
392
    }
 
393
 
 
394
    /**
 
395
     * Remove a stored credential.
 
396
     * Unlike {@link #deleteCredentials}, the the realm name is not
 
397
     * a glob pattern.
 
398
     * <p>
 
399
     * <b>Note:</b> If the native credentials store is disabled, this
 
400
     *              method will always return <code>null</code>.
 
401
     *
 
402
     * @param configDir The path to the configuration directory; if
 
403
     *        <code>null</code>, the default (system-specific) user
 
404
     *        configuration path will be used.
 
405
     * @param kind The kind of the credential; may not be <code>null</code>.
 
406
     * @param realm The realm name; may not be <code>null</code>.
 
407
     * @return the deleted credential, or <code>null</code> if not found.
 
408
     */
 
409
    public static Credential removeCredential(String configDir,
 
410
                                              Credential.Kind kind,
 
411
                                              String realm)
 
412
        throws ClientException, SubversionException
 
413
    {
 
414
        return configLib.removeCredential(configDir, kind, realm);
 
415
    }
 
416
 
 
417
    // ### TODO: There are currently no proper APIs in Subversion for
 
418
    //           adding credentials. This method is a placeholder.
 
419
    //
 
420
    ///**
 
421
    // * Store a new credential, or replace an existing credential.
 
422
    // * <p>
 
423
    // * <b>Note:</b> If the native credentials store is disabled, this
 
424
    // *              method will always return <code>null</code>.
 
425
    // *
 
426
    // * @param configDir The path to the configuration directory; if
 
427
    // *        <code>null</code>, the default (system-specific) user
 
428
    // *        configuration path will be used.
 
429
    // * @param credential The credential to store.
 
430
    // * @param replace If <code>true</code>, any existing matching
 
431
    // *        credential will be replaced.
 
432
    // *
 
433
    // * @return the stored credential. If <code>replace</code> was
 
434
    // * <code>false</code>, and a credential with the same kind and
 
435
    // * for the same realm exists, it will be returned. If the given
 
436
    // * credential was successfully added, the same object reference
 
437
    // * will be returned (the calling code can compare reference values
 
438
    // * to determine this). Will return <code>null</code> if the
 
439
    // * credential could not be stored for any reason.
 
440
    // */
 
441
    //public static Credential addCredential(String configDir,
 
442
    //                                       Credential credential,
 
443
    //                                       boolean replace)
 
444
    //    throws ClientException, SubversionException
 
445
    //{
 
446
    //    return configLib.addCredential(configDir, credential, replace);
 
447
    //}
 
448
 
 
449
    /**
 
450
     * Find stored credentials that match the given search criteria.
 
451
     * <p>
 
452
     * <b>Note:</b> If the native credentials store is disabled, this
 
453
     *              method will always return <code>null</code>.
 
454
     *
 
455
     * @param configDir The path to the configuration directory; if
 
456
     *        <code>null</code>, the default (system-specific) user
 
457
     *        configuration path will be used.
 
458
     * @param kind The kind of the credential; if <code>null</code>,
 
459
     *             all matching credential types will be returned.
 
460
     * @param realmPattern A glob pattern for the realm string;
 
461
     *             if <code>null</code>, all realms will be considered;
 
462
     *             otherwise, only those credentials whose realm matches
 
463
     *             the pattern will be returned.
 
464
     * @param usernamePattern A glob pattern for the username;
 
465
     *             if <code>null</code>, all credentials will be considered;
 
466
     *             otherwise, only those credentials that have a username,
 
467
     *             and where the username matches the pattern, will be
 
468
     *             returned.
 
469
     * @param hostnamePattern A glob pattern for the hostnames of a
 
470
     *             server certificate; if <code>null</code>, all
 
471
     *             credntials will be considered; otherwise, only
 
472
     *             those credentials that have a server certificate
 
473
     *             with a hostname that matches the pattern will be
 
474
     *             returned.
 
475
     * @param textPattern A glob pattern that must match any textual
 
476
     *             information in a credential, for example, a realm,
 
477
     *             username, certificate details, etc; passwords, passphrases
 
478
     *             and other info considered secret will not be matched;
 
479
     * @return the list of matching credentials.
 
480
     */
 
481
    public static List<Credential>
 
482
        searchCredentials(String configDir,
 
483
                          Credential.Kind kind,
 
484
                          String realmPattern,
 
485
                          String usernamePattern,
 
486
                          String hostnamePattern,
 
487
                          String textPattern)
 
488
        throws ClientException, SubversionException
 
489
    {
 
490
        return configLib.searchCredentials(configDir, kind, realmPattern,
 
491
                                           usernamePattern, hostnamePattern,
 
492
                                           textPattern);
 
493
    }
 
494
 
 
495
    //
 
496
    // Diff and Merge
 
497
    //
 
498
    private static final DiffLib diffLib = new DiffLib();
 
499
 
 
500
    /**
 
501
     * Options to control the behaviour of the file diff routines.
 
502
     */
 
503
    public static class DiffOptions
 
504
    {
 
505
        /**
 
506
         * To what extent whitespace should be ignored when comparing lines.
 
507
         */
 
508
        public enum IgnoreSpace
 
509
        {
 
510
            /** Do not ignore whitespace */
 
511
            none,
 
512
 
 
513
            /**
 
514
             * Ignore changes in sequences of whitespace characters,
 
515
             * treating each sequence of whitespace characters as a
 
516
             * single space.
 
517
             */
 
518
            change,
 
519
 
 
520
            /** Ignore all whitespace characters. */
 
521
            all
 
522
        }
 
523
 
 
524
        /**
 
525
         * @param ignoreSpace Whether and how to ignore space differences
 
526
         *        in the files. The default is {@link IgnoreSpace#none}.
 
527
         * @param ignoreEolStyle Whether to treat all end-of-line
 
528
         *        markers the same when comparing lines.  The default
 
529
         *        is <code>false</code>.
 
530
         * @param showCFunction Whether the "@@" lines of the unified
 
531
         *        diff output should include a prefix of the nearest
 
532
         *        preceding line that starts with a character that
 
533
         *        might be the initial character of a C language
 
534
         *        identifier. The default is <code>false</code>.
 
535
         */
 
536
        public DiffOptions(IgnoreSpace ignoreSpace,
 
537
                           boolean ignoreEolStyle,
 
538
                           boolean showCFunction)
 
539
        {
 
540
            this.ignoreSpace = ignoreSpace;
 
541
            this.ignoreEolStyle = ignoreEolStyle;
 
542
            this.showCFunction = showCFunction;
 
543
            this.contextSize = -1;
 
544
        }
 
545
 
 
546
        /**
 
547
         * Like the {@see #DiffOptions(IgnoreSpace,boolean,boolean)},
 
548
         * but with an additional parameter.
 
549
         * @param contextSize If this is greater than 0, then this
 
550
         * number of context lines will be used in the generated diff
 
551
         * output. Otherwise the legacy compile time default will be
 
552
         * used.
 
553
         */
 
554
        public DiffOptions(IgnoreSpace ignoreSpace,
 
555
                           boolean ignoreEolStyle,
 
556
                           boolean showCFunction,
 
557
                           int contextSize)
 
558
        {
 
559
            this.ignoreSpace = ignoreSpace;
 
560
            this.ignoreEolStyle = ignoreEolStyle;
 
561
            this.showCFunction = showCFunction;
 
562
            this.contextSize = contextSize;
 
563
        }
 
564
 
 
565
        public final IgnoreSpace ignoreSpace;
 
566
        public final boolean ignoreEolStyle;
 
567
        public final boolean showCFunction;
 
568
        public final int contextSize;
 
569
    }
 
570
 
 
571
    /** Style for displaying conflicts in merge output. */
 
572
    public enum ConflictDisplayStyle
 
573
    {
 
574
        /** Display modified and latest, with conflict markers. */
 
575
        modified_latest,
 
576
 
 
577
        /**
 
578
         * Like <code>modified_latest</code>, but with an extra effort
 
579
         * to identify common sequences between modified and latest.
 
580
         */
 
581
        resolved_modified_latest,
 
582
 
 
583
        /** Display modified, original, and latest, with conflict markers. */
 
584
        modified_original_latest,
 
585
 
 
586
        /** Just display modified, with no markers. */
 
587
        modified,
 
588
 
 
589
        /** Just display latest, with no markers. */
 
590
        latest,
 
591
 
 
592
        /**
 
593
         * Like <code>modified_original_latest</code>, but
 
594
         * <em>only<em> showing conflicts.
 
595
         */
 
596
        only_conflicts
 
597
    }
 
598
 
 
599
    /**
 
600
     * Given two versions of a file, base (<code>originalFile</code>)
 
601
     * and current (<code>modifiedFile</code>), show differences between
 
602
     * them in unified diff format.
 
603
     *
 
604
     * @param originalFile The base file version (unmodified)
 
605
     * @param modifiedFile The incoming file version (locally modified)
 
606
     * @param diffOptions Options controlling how files are compared.
 
607
     *        May be <code>null</code>.
 
608
     * @param originalHeader The header to display for the base file
 
609
     *        in the unidiff index block. If it is <code>null</code>,
 
610
     *        the <code>originalFile</code> path and its modification
 
611
     *        time will be used instead.
 
612
     * @param modifiedHeader The header to display for the current
 
613
     *        file in the unidiff index block. If it is <code>null</code>,
 
614
     *        the <code>currentFile</code> path and its modification
 
615
     *        time will be used instead.
 
616
     * @param headerEncoding The character encoding of the unidiff headers.
 
617
     * @param relativeToDir If this parameter is not <null>, it must
 
618
     *        be the path of a (possibly non-immediate) parent of both
 
619
     *        <code>originalFile</code> and <code>modifiedFile</code>.
 
620
     *        This path will be stripped from the beginning of those
 
621
     *        file names if they are used in the unidiff index header.
 
622
     * @param resultStream The stream that receives the merged output.
 
623
     * @return <code>true</code> if there were differences between the files.
 
624
     * @throws ClientException
 
625
     */
 
626
    public static boolean fileDiff(String originalFile,
 
627
                                   String modifiedFile,
 
628
                                   SVNUtil.DiffOptions diffOptions,
 
629
 
 
630
                                   String originalHeader,
 
631
                                   String modifiedHeader,
 
632
                                   String headerEncoding,
 
633
                                   String relativeToDir,
 
634
 
 
635
                                   OutputStream resultStream)
 
636
        throws ClientException
 
637
    {
 
638
        // ### TODO: Support cancellation as in svn_diff_file_output_unified3.
 
639
        return diffLib.fileDiff(originalFile, modifiedFile, diffOptions,
 
640
                                originalHeader, modifiedHeader,
 
641
                                headerEncoding,
 
642
                                relativeToDir, resultStream);
 
643
    }
 
644
 
 
645
 
 
646
    /**
 
647
     * Given three versions of a file, base (<code>originalFile</code>),
 
648
     * incoming (<code>modifiedFile</code>) and current
 
649
     * (<code>latestFile</code>, produce a merged result, possibly
 
650
     * displaying conflict markers.
 
651
     *
 
652
     * @param originalFile The base file version (common ancestor)
 
653
     * @param modifiedFile The incoming file version (modified elsewhere)
 
654
     * @param latestFile The current file version (locally modified)
 
655
     * @param diffOptions Options controlling how files are compared.
 
656
     *        May be <code>null</code>.
 
657
     * @param conflictOriginal Optional custom conflict marker for
 
658
     *        the <code>originalFile</code> contents.
 
659
     * @param conflictModified Optional custom conflict marker for
 
660
     *        the <code>modifiedFile</code> contents.
 
661
     * @param conflictLatest Optional custom conflict marker for
 
662
     *        the <code>latestFile</code> contents.
 
663
     * @param conflictSeparator Optional custom conflict separator.
 
664
     * @param conflictStyle Determines how conflicts are displayed.
 
665
     * @param resultStream The stream that receives the merged output.
 
666
     * @return <code>true</code> if there were any conflicts.
 
667
     * @throws ClientException
 
668
     */
 
669
    public static boolean fileMerge(String originalFile,
 
670
                                    String modifiedFile,
 
671
                                    String latestFile,
 
672
                                    DiffOptions diffOptions,
 
673
 
 
674
                                    String conflictOriginal,
 
675
                                    String conflictModified,
 
676
                                    String conflictLatest,
 
677
                                    String conflictSeparator,
 
678
                                    ConflictDisplayStyle conflictStyle,
 
679
 
 
680
                                    OutputStream resultStream)
 
681
        throws ClientException
 
682
    {
 
683
        return diffLib.fileMerge(originalFile, modifiedFile, latestFile,
 
684
                                 diffOptions,
 
685
                                 conflictOriginal, conflictModified,
 
686
                                 conflictLatest, conflictSeparator,
 
687
                                 conflictStyle, resultStream);
 
688
    }
 
689
 
 
690
    //
 
691
    // Property validation and parsing
 
692
    //
 
693
    private static final PropLib propLib = new PropLib();
 
694
 
 
695
    /**
 
696
     * Validate the value of an <code>svn:</code> property on file or
 
697
     * directory and return a canonical representation of its value.
 
698
     * @param name The name of the property (must be a valid svn: property)
 
699
     * @param value The property's value
 
700
     * @param path The path or URL of the file or directory that
 
701
     *        owns the property; only used for error messages
 
702
     * @param kind The node kind of the file or dir that owns the property
 
703
     * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
 
704
     *        tye file's mime-type, used for extra validation for the
 
705
     *        <code>svn:eol-style</code> property. If it is <code>null</code>,
 
706
     *        the extra validation will be skipped.
 
707
     * @return a canonicalized representation of the property value
 
708
     * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
 
709
     */
 
710
    public static byte[] canonicalizeNodeProperty(
 
711
        String name, byte[] value, String path, NodeKind kind,
 
712
        String mimeType)
 
713
        throws ClientException
 
714
    {
 
715
        return propLib.canonicalizeNodeProperty(
 
716
            name, value, path, kind, mimeType, null);
 
717
    }
 
718
 
 
719
    /**
 
720
     * Validate the value of an <code>svn:</code> property on file or
 
721
     * directory and return a canonical representation of its value.
 
722
     * @param name The name of the property (must be a valid svn: property)
 
723
     * @param value The property's value
 
724
     * @param path The path or URL of the file or directory that
 
725
     *        owns the property; only used for error messages
 
726
     * @param kind The node kind of the file or dir that owns the property
 
727
     * @param mimeType If <code>kind</code> is {@link NodeKind.file}, this is
 
728
     *        tye file's mime-type, used for extra validation for the
 
729
     *        <code>svn:eol-style</code> property. If it is <code>null</code>,
 
730
     *        the extra validation will be skipped.
 
731
     * @param fileContents A stream with the file's contents. Only used
 
732
     *        to check for line-ending consistency when validating the
 
733
     *        <code>svn:eol-style</code> property, and only when
 
734
     *        <code>kind</code> is {@link NodeKind.file} and
 
735
     *        <code>mimeType</code> is not <code>null</code>.
 
736
     * @return a canonicalized representation of the property value
 
737
     * @see http://subversion.apache.org/docs/api/latest/group__svn__wc__properties.html#ga83296313ec59cc825176224ac8282ec2
 
738
     */
 
739
    public static byte[] canonicalizeNodeProperty(
 
740
        String name, byte[] value, String path, NodeKind kind,
 
741
        String mimeType, InputStream fileContents)
 
742
        throws ClientException
 
743
    {
 
744
        return propLib.canonicalizeNodeProperty(
 
745
            name, value, path, kind, mimeType, fileContents);
 
746
    }
 
747
 
 
748
    /**
 
749
     * Parse <code>description</code>, assuming it is an externals
 
750
     * specification in the format required for the
 
751
     * <code>svn:externals</code> property, and return a list of
 
752
     * parsed external items.
 
753
     * @param description The externals description.
 
754
     * @param parentDirectory Used to construct error messages.
 
755
     * @param canonicalizeUrl Whe <code>true</code>, canonicalize the
 
756
     *     <code>url</code> member of the returned objects. If the
 
757
     *     <code>url</code> member refers to an absolute URL, it will
 
758
     *     be canonicalized as URL consistent with the way URLs are
 
759
     *     canonicalized throughout the Subversion API. If, however,
 
760
     *     the <code>url</code> member makes use of the recognized
 
761
     *     (SVN-specific) relative URL syntax for
 
762
     *     <code>svn:externals</code>, "canonicalization" is an
 
763
     *     ill-defined concept which may even result in munging the
 
764
     *     relative URL syntax beyond recognition. You've been warned.
 
765
     * @return a list of {@link ExternalItem}s
 
766
     */
 
767
    public static List<ExternalItem> parseExternals(byte[] description,
 
768
                                                    String parentDirectory,
 
769
                                                    boolean canonicalizeUrl)
 
770
        throws ClientException
 
771
    {
 
772
        return propLib.parseExternals(description, parentDirectory,
 
773
                                      canonicalizeUrl);
 
774
    }
 
775
 
 
776
    /**
 
777
     * Unparse and list of external items into a format suitable for
 
778
     * the value of the <code>svn:externals</code> property and
 
779
     * validate the result.
 
780
     * @param items The list of {@link ExternalItem}s
 
781
     * @param parentDirectory Used to construct error messages.
 
782
     * @param compatibleWithSvn1_5 When <code>true</code>, the format
 
783
     *     of the returned property value will be compatible with
 
784
     *     clients older than Subversion 1.5.
 
785
     */
 
786
    public static byte[] unparseExternals(List<ExternalItem> items,
 
787
                                          String parentDirectory)
 
788
        throws SubversionException
 
789
    {
 
790
        return propLib.unparseExternals(items, parentDirectory, false);
 
791
    }
 
792
 
 
793
    /**
 
794
     * Unparse and list of external items into a format suitable for
 
795
     * the value of the <code>svn:externals</code> property compatible
 
796
     * with Subversion clients older than release 1.5, and validate
 
797
     * the result.
 
798
     * @param items The list of {@link ExternalItem}s
 
799
     * @param parentDirectory Used to construct error messages.
 
800
     */
 
801
    public static byte[] unparseExternalsForAncientUnsupportedClients(
 
802
        List<ExternalItem> items, String parentDirectory)
 
803
        throws SubversionException
 
804
    {
 
805
        return propLib.unparseExternals(items, parentDirectory, true);
 
806
    }
 
807
 
 
808
    /**
 
809
     * If the URL in <code>external</code> is relative, resolve it to
 
810
     * an absolute URL, using <code>reposRootUrl</code> and
 
811
     * <code>parentDirUrl</code> to provide contest.
 
812
     *<p>
 
813
     * Regardless if the URL is absolute or not, if there are no
 
814
     * errors, the returned URL will be canonicalized.
 
815
     *<p>
 
816
     * The following relative URL formats are supported:
 
817
     * <dl>
 
818
     *  <dt><code>../</code></dt>
 
819
     *  <dd>relative to the parent directory of the external</dd>
 
820
     *  <dt><code>^/</code></dt>
 
821
     *  <dd>relative to the repository root</dd>
 
822
     *  <dt><code>//</code></dt>
 
823
     *  <dd>relative to the scheme</dd>
 
824
     *  <dt><code>/</code></dt>
 
825
     *  <dd>relative to the server's hostname</dd>
 
826
     * </dl>
 
827
     *<p>
 
828
     * The <code>../<code> and ^/ relative URLs may use <code>..</code>
 
829
     * to remove path elements up to the server root.
 
830
     *<p>
 
831
     * The external URL should not be canonicalized before calling
 
832
     * this function, as otherwise the scheme relative URL
 
833
     * '<code>//host/some/path</code>' would have been canonicalized
 
834
     * to '<code>/host/some/path</code>' and we would not be able to
 
835
     * match on the leading '<code>//</code>'.
 
836
    */
 
837
    public static String resolveExternalsUrl(ExternalItem external,
 
838
                                             String reposRootUrl,
 
839
                                             String parentDirUrl)
 
840
        throws ClientException
 
841
    {
 
842
        return propLib.resolveExternalsUrl(
 
843
                   external, reposRootUrl, parentDirUrl);
 
844
    }
 
845
 
 
846
    //
 
847
    // Newline translation and keyword expansion
 
848
    //
 
849
    private static final SubstLib substLib = new SubstLib();
 
850
 
 
851
    /**
 
852
     * Use the linefeed code point ('<code>\x0a</code>')
 
853
     * for the newline separator.
 
854
     * @see translateStream
 
855
     * @see untranslateStream
 
856
     */
 
857
    public static final byte[] EOL_LF = SubstLib.EOL_LF;
 
858
 
 
859
    /**
 
860
     * Use the carraige-return code point ('<code>\x0d</code>')
 
861
     * for the newline separator.
 
862
     * @see translateStream
 
863
     * @see untranslateStream
 
864
     */
 
865
    public static final byte[] EOL_CR = SubstLib.EOL_CR;
 
866
 
 
867
    /**
 
868
     * Use carriage-return/linefeed sequence ('<code>\x0d\x0a</code>')
 
869
     * for the newline separator.
 
870
     * @see translateStream
 
871
     * @see untranslateStream
 
872
     */
 
873
    public static final byte[] EOL_CRLF = SubstLib.EOL_CRLF;
 
874
 
 
875
 
 
876
    /**
 
877
     * Build a dictionary of expanded keyword values, given the
 
878
     * contents of a file's <code>svn:keywords</code> property, its
 
879
     * revision, URL, the date it was committed on, the author of the
 
880
     * commit and teh URL of the repository root.
 
881
     *<p>
 
882
     * Custom keywords defined in <code>svn:keywords</code> properties
 
883
     * are expanded using the provided parameters and in accordance
 
884
     * with the following format substitutions in the
 
885
     * <code>keywordsValue</code>:
 
886
     * <dl>
 
887
     *   <dt><code>%a</dt></code>
 
888
     * <dd>The author.</dd>
 
889
     *   <dt><code>%b</dt></code>
 
890
     * <dd>The basename of the URL.</dd>
 
891
     *   <dt><code>%d</dt></code>
 
892
     * <dd>Short format of the date.</dd>
 
893
     *   <dt><code>%D</dt></code>
 
894
     * <dd>Long format of the date.</dd>
 
895
     *   <dt><code>%P</dt></code>
 
896
     * <dd>The file's path, relative to the repository root URL.</dd>
 
897
     *   <dt><code>%r</dt></code>
 
898
     * <dd>The revision.</dd>
 
899
     *   <dt><code>%R</dt></code>
 
900
     * <dd>The URL to the root of the repository.</dd>
 
901
     *   <dt><code>%u</dt></code>
 
902
     * <dd>The URL of the file.</dd>
 
903
     *   <dt><code>%_</dt></code>
 
904
     * <dd>A space (keyword definitions cannot contain a literal space).</dd>
 
905
     *   <dt><code>%%</dt></code>
 
906
     * <dd>A literal '%'.</dd>
 
907
     *   <dt><code>%H</dt></code>
 
908
     * <dd>Equivalent to <code>%P%_%r%_%d%_%a</code>.</dd>
 
909
     *   <dt><code>%I</dt></code>
 
910
     * <dd>Equivalent to <code>%b%_%r%_%d%_%a</code>.</dd>
 
911
     * </dl>
 
912
     *<p>
 
913
     * Custom keywords are defined by appending '=' to the keyword
 
914
     * name, followed by a string containing any combination of the
 
915
     * format substitutions.
 
916
     *<p>
 
917
     * Any of the <code>revision</code>, <code>url</code>,
 
918
     * <code>reposRootUrl</code>, <code>date</code> and
 
919
     * <code>author</code> parameters may be <code>null</code>, or
 
920
     * {@link Revision#SVN_INVALID_REVNUM} for <code>revision</code>,
 
921
     * to indicate that the information is not present. Each piece of
 
922
     * information that is not present expands to the empty string
 
923
     * wherever it appears in an expanded keyword value.  (This can
 
924
     * result in multiple adjacent spaces in the expansion of a
 
925
     * multi-valued keyword such as "<code>Id</code>".)
 
926
     */
 
927
    public static Map<String, byte[]> buildKeywords(byte[] keywordsValue,
 
928
                                                    long revision,
 
929
                                                    String url,
 
930
                                                    String reposRootUrl,
 
931
                                                    Date date,
 
932
                                                    String author)
 
933
        throws SubversionException, ClientException
 
934
    {
 
935
        return substLib.buildKeywords(keywordsValue, revision,
 
936
                                      url, reposRootUrl, date, author);
 
937
    }
 
938
 
 
939
    /**
 
940
     * Return a stream which performs end-of-line translation and
 
941
     * keyword expansion when read from.
 
942
     *<p>
 
943
     * <b>Important:</b> Make sure you close the returned stream to
 
944
     * ensure all data are flushed and cleaned up (this will also
 
945
     * close the provided stream and dispose the related netive
 
946
     * object).
 
947
     *<p>
 
948
     * If <code>eolMarker</code> is not <code>null</code>, replace
 
949
     * whatever any end-of-line sequences in the input with
 
950
     * <code>eolMarker</code>.  If the input has an inconsistent line
 
951
     * ending style, then:
 
952
     * <ul>
 
953
     *   <li>if <code>repairEol</code> is <code>false</code>, then a
 
954
     *       subsequent read or other operation on the stream will
 
955
     *       generate an error when the inconsistency is detected;</li>
 
956
     *   <li>if <code>repaorEol</code> is <code>true</code>, convert any
 
957
     *       line ending to <code>eolMarker</code>.<br/>
 
958
     *       Recognized line endings are: "<code>\n</code>",
 
959
     *       "<code>\r</code>", and "<code>\r\n</code>".</li>
 
960
     * </ul>
 
961
     *<p>
 
962
     * Expand or contract keywords using the contents of
 
963
     * <code>keywords</code> as the new values.  If
 
964
     * <code>expandKeywords</code> is <code>true</code>, expand
 
965
     * contracted keywords and re-expand expanded keywords; otherwise,
 
966
     * contract expanded keywords and ignore contracted ones.
 
967
     * Keywords not found in the dictionary are ignored (not
 
968
     * contracted or expanded).  If the <code>keywords</code> itself
 
969
     * is <code>null</code>, keyword substitution will be altogether
 
970
     * ignored.
 
971
     *<p>
 
972
     * Detect only keywords that are no longer than
 
973
     * <code>SVN_KEYWORD_MAX_LEN</code> bytes (currently: 255),
 
974
     * including the delimiters and the keyword itself.
 
975
     *<p>
 
976
     * Recommendation: if <code>expandKeywords</code> is
 
977
     * <code>false</code>, then you don't care about the keyword
 
978
     * values, so just put <code>null</code> values into the
 
979
     * <code>keywords</code> dictionary.
 
980
     *<p>
 
981
     * If the inner stream implements marking and seeking via
 
982
     * {@link InputStream#mark} and {@link InputStream#reset}, the
 
983
     * translated stream will too.
 
984
     *
 
985
     * @param source the source (untranslated) stream.
 
986
     * @param eolMarker the byte sequence to use as the end-of-line marker;
 
987
     *     must be one of {@link #EOL_LF}, {@link #EOL_CR}
 
988
     *     or {@link #EOL_CRLF}.
 
989
     * @param repairEol flag to repair end-of-lines; see above
 
990
     * @param keywords the keyword dictionary; see {@link buildKeywords}
 
991
     * @param expandKeywords flag to expand keywords
 
992
     */
 
993
    public static InputStream translateStream(InputStream source,
 
994
                                              byte[] eolMarker,
 
995
                                              boolean repairEol,
 
996
                                              Map<String, byte[]> keywords,
 
997
                                              boolean expandKeywords)
 
998
        throws SubversionException, ClientException
 
999
    {
 
1000
        return substLib.translateInputStream(
 
1001
                    source, eolMarker, repairEol,
 
1002
                    keywords, true, expandKeywords,
 
1003
                    null, Revision.SVN_INVALID_REVNUM,
 
1004
                    null, null, null, null);
 
1005
    }
 
1006
 
 
1007
    /**
 
1008
     * Expand keywords and return a stream which performs end-of-line
 
1009
     * translation and keyword expansion when read from.
 
1010
     * @see buildKeywords
 
1011
     * @see translateStream(InputStream,byte[],boolean,Map,boolean)
 
1012
     */
 
1013
    public static InputStream translateStream(InputStream source,
 
1014
                                              byte[] eolMarker,
 
1015
                                              boolean repairEol,
 
1016
                                              boolean expandKeywords,
 
1017
                                              byte[] keywordsValue,
 
1018
                                              long revision,
 
1019
                                              String url,
 
1020
                                              String reposRootUrl,
 
1021
                                              Date date,
 
1022
                                              String author)
 
1023
        throws SubversionException, ClientException
 
1024
    {
 
1025
        return substLib.translateInputStream(
 
1026
                    source, eolMarker, repairEol,
 
1027
                    null, false, expandKeywords,
 
1028
                    keywordsValue, revision,
 
1029
                    url, reposRootUrl, date, author);
 
1030
    }
 
1031
 
 
1032
    /**
 
1033
     * Return a stream which performs end-of-line translation and
 
1034
     * keyword expansion when written to. Behaves like
 
1035
     * {@link #translateStream(InputStream,byte[],boolean,Map,boolean)},
 
1036
     * except that it translates an <code>OutputStream</code> and never
 
1037
     * supports marking and seeking.
 
1038
     */
 
1039
    public static OutputStream translateStream(OutputStream destination,
 
1040
                                               byte[] eolMarker,
 
1041
                                               boolean repairEol,
 
1042
                                               Map<String, byte[]> keywords,
 
1043
                                               boolean expandKeywords)
 
1044
        throws SubversionException, ClientException
 
1045
    {
 
1046
        return substLib.translateOutputStream(
 
1047
                    destination, eolMarker, repairEol,
 
1048
                    keywords, true, expandKeywords,
 
1049
                    null, Revision.SVN_INVALID_REVNUM,
 
1050
                    null, null, null, null);
 
1051
    }
 
1052
 
 
1053
    /**
 
1054
     * Expand keywords and return a stream which performs end-of-line
 
1055
     * translation and keyword expansion when written to.
 
1056
     * @see buildKeywords
 
1057
     * @see translateStream(OutputStream,byte[],boolean,Map,boolean)
 
1058
     */
 
1059
    public static OutputStream translateStream(OutputStream destination,
 
1060
                                               byte[] eolMarker,
 
1061
                                               boolean repairEol,
 
1062
                                               boolean expandKeywords,
 
1063
                                               byte[] keywordsValue,
 
1064
                                               long revision,
 
1065
                                               String url,
 
1066
                                               String reposRootUrl,
 
1067
                                               Date date,
 
1068
                                               String author)
 
1069
        throws SubversionException, ClientException
 
1070
    {
 
1071
        return substLib.translateOutputStream(
 
1072
                    destination, eolMarker, repairEol,
 
1073
                    null, false, expandKeywords,
 
1074
                    keywordsValue, revision,
 
1075
                    url, reposRootUrl, date, author);
 
1076
    }
 
1077
}