You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Paths.java 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (C) 2016, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.util;
  44. import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
  45. import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
  46. /**
  47. * Utility functions for paths inside of a Git repository.
  48. *
  49. * @since 4.2
  50. */
  51. public class Paths {
  52. /**
  53. * Remove trailing {@code '/'} if present.
  54. *
  55. * @param path
  56. * input path to potentially remove trailing {@code '/'} from.
  57. * @return null if {@code path == null}; {@code path} after removing a
  58. * trailing {@code '/'}.
  59. */
  60. public static String stripTrailingSeparator(String path) {
  61. if (path == null || path.isEmpty()) {
  62. return path;
  63. }
  64. int i = path.length();
  65. if (path.charAt(path.length() - 1) != '/') {
  66. return path;
  67. }
  68. do {
  69. i--;
  70. } while (path.charAt(i - 1) == '/');
  71. return path.substring(0, i);
  72. }
  73. /**
  74. * Compare two paths according to Git path sort ordering rules.
  75. *
  76. * @param aPath
  77. * first path buffer. The range {@code [aPos, aEnd)} is used.
  78. * @param aPos
  79. * index into {@code aPath} where the first path starts.
  80. * @param aEnd
  81. * 1 past last index of {@code aPath}.
  82. * @param aMode
  83. * mode of the first file. Trees are sorted as though
  84. * {@code aPath[aEnd] == '/'}, even if aEnd does not exist.
  85. * @param bPath
  86. * second path buffer. The range {@code [bPos, bEnd)} is used.
  87. * @param bPos
  88. * index into {@code bPath} where the second path starts.
  89. * @param bEnd
  90. * 1 past last index of {@code bPath}.
  91. * @param bMode
  92. * mode of the second file. Trees are sorted as though
  93. * {@code bPath[bEnd] == '/'}, even if bEnd does not exist.
  94. * @return <0 if {@code aPath} sorts before {@code bPath};
  95. * 0 if the paths are the same;
  96. * >0 if {@code aPath} sorts after {@code bPath}.
  97. */
  98. public static int compare(byte[] aPath, int aPos, int aEnd, int aMode,
  99. byte[] bPath, int bPos, int bEnd, int bMode) {
  100. int cmp = coreCompare(
  101. aPath, aPos, aEnd, aMode,
  102. bPath, bPos, bEnd, bMode);
  103. if (cmp == 0) {
  104. cmp = lastPathChar(aMode) - lastPathChar(bMode);
  105. }
  106. return cmp;
  107. }
  108. /**
  109. * Compare two paths, checking for identical name.
  110. * <p>
  111. * Unlike {@code compare} this method returns {@code 0} when the paths have
  112. * the same characters in their names, even if the mode differs. It is
  113. * intended for use in validation routines detecting duplicate entries.
  114. * <p>
  115. * Returns {@code 0} if the names are identical and a conflict exists
  116. * between {@code aPath} and {@code bPath}, as they share the same name.
  117. * <p>
  118. * Returns {@code <0} if all possibles occurrences of {@code aPath} sort
  119. * before {@code bPath} and no conflict can happen. In a properly sorted
  120. * tree there are no other occurrences of {@code aPath} and therefore there
  121. * are no duplicate names.
  122. * <p>
  123. * Returns {@code >0} when it is possible for a duplicate occurrence of
  124. * {@code aPath} to appear later, after {@code bPath}. Callers should
  125. * continue to examine candidates for {@code bPath} until the method returns
  126. * one of the other return values.
  127. *
  128. * @param aPath
  129. * first path buffer. The range {@code [aPos, aEnd)} is used.
  130. * @param aPos
  131. * index into {@code aPath} where the first path starts.
  132. * @param aEnd
  133. * 1 past last index of {@code aPath}.
  134. * @param bPath
  135. * second path buffer. The range {@code [bPos, bEnd)} is used.
  136. * @param bPos
  137. * index into {@code bPath} where the second path starts.
  138. * @param bEnd
  139. * 1 past last index of {@code bPath}.
  140. * @param bMode
  141. * mode of the second file. Trees are sorted as though
  142. * {@code bPath[bEnd] == '/'}, even if bEnd does not exist.
  143. * @return &lt;0 if no duplicate name could exist;
  144. * 0 if the paths have the same name;
  145. * &gt;0 other {@code bPath} should still be checked by caller.
  146. */
  147. public static int compareSameName(
  148. byte[] aPath, int aPos, int aEnd,
  149. byte[] bPath, int bPos, int bEnd, int bMode) {
  150. return coreCompare(
  151. aPath, aPos, aEnd, TYPE_TREE,
  152. bPath, bPos, bEnd, bMode);
  153. }
  154. private static int coreCompare(
  155. byte[] aPath, int aPos, int aEnd, int aMode,
  156. byte[] bPath, int bPos, int bEnd, int bMode) {
  157. while (aPos < aEnd && bPos < bEnd) {
  158. int cmp = (aPath[aPos++] & 0xff) - (bPath[bPos++] & 0xff);
  159. if (cmp != 0) {
  160. return cmp;
  161. }
  162. }
  163. if (aPos < aEnd) {
  164. return (aPath[aPos] & 0xff) - lastPathChar(bMode);
  165. }
  166. if (bPos < bEnd) {
  167. return lastPathChar(aMode) - (bPath[bPos] & 0xff);
  168. }
  169. return 0;
  170. }
  171. private static int lastPathChar(int mode) {
  172. if ((mode & TYPE_MASK) == TYPE_TREE) {
  173. return '/';
  174. }
  175. return 0;
  176. }
  177. private Paths() {
  178. }
  179. }