1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.notes;
45
46 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
47 import static org.eclipse.jgit.lib.Constants.encodeASCII;
48 import static org.eclipse.jgit.lib.FileMode.TREE;
49 import static org.eclipse.jgit.util.RawParseUtils.parseHexInt4;
50
51 import java.io.IOException;
52
53 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
54 import org.eclipse.jgit.lib.AbbreviatedObjectId;
55 import org.eclipse.jgit.lib.FileMode;
56 import org.eclipse.jgit.lib.MutableObjectId;
57 import org.eclipse.jgit.lib.ObjectId;
58 import org.eclipse.jgit.lib.ObjectReader;
59 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
60
61
62 final class NoteParser extends CanonicalTreeParser {
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 static InMemoryNoteBucket parse(AbbreviatedObjectId prefix,
89 final ObjectId treeId, final ObjectReader reader)
90 throws IOException {
91 return new NoteParser(prefix, reader, treeId).parse();
92 }
93
94 private final int prefixLen;
95
96 private final int pathPadding;
97
98 private NonNoteEntry firstNonNote;
99
100 private NonNoteEntry lastNonNote;
101
102 private NoteParser(AbbreviatedObjectId prefix, ObjectReader r, ObjectId t)
103 throws IncorrectObjectTypeException, IOException {
104 super(encodeASCII(prefix.name()), r, t);
105 prefixLen = prefix.length();
106
107
108
109 pathPadding = 0 < prefixLen ? 1 : 0;
110 if (0 < pathPadding)
111 System.arraycopy(path, 0, path, pathPadding, prefixLen);
112 }
113
114 private InMemoryNoteBucket parse() {
115 InMemoryNoteBucket r = parseTree();
116 r.nonNotes = firstNonNote;
117 return r;
118 }
119
120 private InMemoryNoteBucket parseTree() {
121 for (; !eof(); next(1)) {
122 if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH && isHex())
123 return parseLeafTree();
124
125 else if (getNameLength() == 2 && isHex() && isTree())
126 return parseFanoutTree();
127
128 else
129 storeNonNote();
130 }
131
132
133 return new LeafBucket(prefixLen);
134 }
135
136 private LeafBucket parseLeafTree() {
137 final LeafBucketket.html#LeafBucket">LeafBucket leaf = new LeafBucket(prefixLen);
138 final MutableObjectId.html#MutableObjectId">MutableObjectId idBuf = new MutableObjectId();
139
140 for (; !eof(); next(1)) {
141 if (parseObjectId(idBuf))
142 leaf.parseOneEntry(idBuf, getEntryObjectId());
143 else
144 storeNonNote();
145 }
146
147 return leaf;
148 }
149
150 private boolean parseObjectId(MutableObjectId id) {
151 if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH) {
152 try {
153 id.fromString(path, pathPadding);
154 return true;
155 } catch (ArrayIndexOutOfBoundsException notHex) {
156 return false;
157 }
158 }
159 return false;
160 }
161
162 private FanoutBucket parseFanoutTree() {
163 final FanoutBuckett.html#FanoutBucket">FanoutBucket fanout = new FanoutBucket(prefixLen);
164
165 for (; !eof(); next(1)) {
166 final int cell = parseFanoutCell();
167 if (0 <= cell)
168 fanout.setBucket(cell, getEntryObjectId());
169 else
170 storeNonNote();
171 }
172
173 return fanout;
174 }
175
176 private int parseFanoutCell() {
177 if (getNameLength() == 2 && isTree()) {
178 try {
179 return (parseHexInt4(path[pathOffset + 0]) << 4)
180 | parseHexInt4(path[pathOffset + 1]);
181 } catch (ArrayIndexOutOfBoundsException notHex) {
182 return -1;
183 }
184 } else {
185 return -1;
186 }
187 }
188
189 private void storeNonNote() {
190 ObjectId id = getEntryObjectId();
191 FileMode fileMode = getEntryFileMode();
192
193 byte[] name = new byte[getNameLength()];
194 getName(name, 0);
195
196 NonNoteEntry ent = new NonNoteEntry(name, fileMode, id);
197 if (firstNonNote == null)
198 firstNonNote = ent;
199 if (lastNonNote != null)
200 lastNonNote.next = ent;
201 lastNonNote = ent;
202 }
203
204 private boolean isTree() {
205 return TREE.equals(mode);
206 }
207
208 private boolean isHex() {
209 try {
210 for (int i = pathOffset; i < pathLen; i++)
211 parseHexInt4(path[i]);
212 return true;
213 } catch (ArrayIndexOutOfBoundsException fail) {
214 return false;
215 }
216 }
217 }