Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

NoteParser.java 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (C) 2010, 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.notes;
  44. import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
  45. import static org.eclipse.jgit.lib.Constants.encodeASCII;
  46. import static org.eclipse.jgit.lib.FileMode.TREE;
  47. import static org.eclipse.jgit.util.RawParseUtils.parseHexInt4;
  48. import java.io.IOException;
  49. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  50. import org.eclipse.jgit.lib.AbbreviatedObjectId;
  51. import org.eclipse.jgit.lib.FileMode;
  52. import org.eclipse.jgit.lib.MutableObjectId;
  53. import org.eclipse.jgit.lib.ObjectId;
  54. import org.eclipse.jgit.lib.ObjectReader;
  55. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  56. /** Custom tree parser to select note bucket type and load it. */
  57. final class NoteParser extends CanonicalTreeParser {
  58. /**
  59. * Parse a tree object into a {@link NoteBucket} instance.
  60. *
  61. * The type of note tree is automatically detected by examining the items
  62. * within the tree, and allocating the proper storage type based on the
  63. * first note-like entry encountered. Since the method parses by guessing
  64. * the type on the first element, malformed note trees can be read as the
  65. * wrong type of tree.
  66. *
  67. * This method is not recursive, it parses the one tree given to it and
  68. * returns the bucket. If there are subtrees for note storage, they are
  69. * setup as lazy pointers that will be resolved at a later time.
  70. *
  71. * @param prefix
  72. * common hex digits that all notes within this tree share. The
  73. * root tree has {@code prefix.length() == 0}, the first-level
  74. * subtrees should be {@code prefix.length()==2}, etc.
  75. * @param treeId
  76. * the tree to read from the repository.
  77. * @param reader
  78. * reader to access the tree object.
  79. * @return bucket to holding the notes of the specified tree.
  80. * @throws IOException
  81. * {@code treeId} cannot be accessed.
  82. */
  83. static InMemoryNoteBucket parse(AbbreviatedObjectId prefix,
  84. final ObjectId treeId, final ObjectReader reader)
  85. throws IOException {
  86. return new NoteParser(prefix, reader, treeId).parse();
  87. }
  88. private final int prefixLen;
  89. private final int pathPadding;
  90. private NonNoteEntry firstNonNote;
  91. private NonNoteEntry lastNonNote;
  92. private NoteParser(AbbreviatedObjectId prefix, ObjectReader r, ObjectId t)
  93. throws IncorrectObjectTypeException, IOException {
  94. super(encodeASCII(prefix.name()), r, t);
  95. prefixLen = prefix.length();
  96. // Our path buffer has a '/' that we don't want after the prefix.
  97. // Drop it by shifting the path down one position.
  98. pathPadding = 0 < prefixLen ? 1 : 0;
  99. if (0 < pathPadding)
  100. System.arraycopy(path, 0, path, pathPadding, prefixLen);
  101. }
  102. private InMemoryNoteBucket parse() {
  103. InMemoryNoteBucket r = parseTree();
  104. r.nonNotes = firstNonNote;
  105. return r;
  106. }
  107. private InMemoryNoteBucket parseTree() {
  108. for (; !eof(); next(1)) {
  109. if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH && isHex())
  110. return parseLeafTree();
  111. else if (getNameLength() == 2 && isHex() && isTree())
  112. return parseFanoutTree();
  113. else
  114. storeNonNote();
  115. }
  116. // If we cannot determine the style used, assume its a leaf.
  117. return new LeafBucket(prefixLen);
  118. }
  119. private LeafBucket parseLeafTree() {
  120. final LeafBucket leaf = new LeafBucket(prefixLen);
  121. final MutableObjectId idBuf = new MutableObjectId();
  122. for (; !eof(); next(1)) {
  123. if (parseObjectId(idBuf))
  124. leaf.parseOneEntry(idBuf, getEntryObjectId());
  125. else
  126. storeNonNote();
  127. }
  128. return leaf;
  129. }
  130. private boolean parseObjectId(MutableObjectId id) {
  131. if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH) {
  132. try {
  133. id.fromString(path, pathPadding);
  134. return true;
  135. } catch (ArrayIndexOutOfBoundsException notHex) {
  136. return false;
  137. }
  138. }
  139. return false;
  140. }
  141. private FanoutBucket parseFanoutTree() {
  142. final FanoutBucket fanout = new FanoutBucket(prefixLen);
  143. for (; !eof(); next(1)) {
  144. final int cell = parseFanoutCell();
  145. if (0 <= cell)
  146. fanout.setBucket(cell, getEntryObjectId());
  147. else
  148. storeNonNote();
  149. }
  150. return fanout;
  151. }
  152. private int parseFanoutCell() {
  153. if (getNameLength() == 2 && isTree()) {
  154. try {
  155. return (parseHexInt4(path[pathOffset + 0]) << 4)
  156. | parseHexInt4(path[pathOffset + 1]);
  157. } catch (ArrayIndexOutOfBoundsException notHex) {
  158. return -1;
  159. }
  160. } else {
  161. return -1;
  162. }
  163. }
  164. private void storeNonNote() {
  165. ObjectId id = getEntryObjectId();
  166. FileMode fileMode = getEntryFileMode();
  167. byte[] name = new byte[getNameLength()];
  168. getName(name, 0);
  169. NonNoteEntry ent = new NonNoteEntry(name, fileMode, id);
  170. if (firstNonNote == null)
  171. firstNonNote = ent;
  172. if (lastNonNote != null)
  173. lastNonNote.next = ent;
  174. lastNonNote = ent;
  175. }
  176. private boolean isTree() {
  177. return TREE.equals(mode);
  178. }
  179. private boolean isHex() {
  180. try {
  181. for (int i = pathOffset; i < pathLen; i++)
  182. parseHexInt4(path[i]);
  183. return true;
  184. } catch (ArrayIndexOutOfBoundsException fail) {
  185. return false;
  186. }
  187. }
  188. }