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.internal.storage.file;
45
46 import java.io.DataInput;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.text.MessageFormat;
50 import java.util.Arrays;
51
52 import org.eclipse.jgit.internal.JGitText;
53 import org.eclipse.jgit.lib.AnyObjectId;
54 import org.eclipse.jgit.lib.Constants;
55 import org.eclipse.jgit.lib.ObjectId;
56 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
57 import org.eclipse.jgit.util.IO;
58 import org.eclipse.jgit.util.NB;
59
60 import com.googlecode.javaewah.EWAHCompressedBitmap;
61
62
63
64
65
66
67 class PackBitmapIndexV1 extends BasePackBitmapIndex {
68 static final byte[] MAGIC = { 'B', 'I', 'T', 'M' };
69 static final int OPT_FULL = 1;
70
71 private static final int MAX_XOR_OFFSET = 126;
72
73 private final PackIndex packIndex;
74 private final PackReverseIndex reverseIndex;
75 private final EWAHCompressedBitmap commits;
76 private final EWAHCompressedBitmap trees;
77 private final EWAHCompressedBitmap blobs;
78 private final EWAHCompressedBitmap tags;
79
80 private final ObjectIdOwnerMap<StoredBitmap> bitmaps;
81
82 PackBitmapIndexV1(final InputStream fd, PackIndex packIndex,
83 PackReverseIndex reverseIndex) throws IOException {
84 super(new ObjectIdOwnerMap<StoredBitmap>());
85 this.packIndex = packIndex;
86 this.reverseIndex = reverseIndex;
87 this.bitmaps = getBitmaps();
88
89 final byte[] scratch = new byte[32];
90 IO.readFully(fd, scratch, 0, scratch.length);
91
92
93 for (int i = 0; i < MAGIC.length; i++) {
94 if (scratch[i] != MAGIC[i]) {
95 byte[] actual = new byte[MAGIC.length];
96 System.arraycopy(scratch, 0, actual, 0, MAGIC.length);
97 throw new IOException(MessageFormat.format(
98 JGitText.get().expectedGot, Arrays.toString(MAGIC),
99 Arrays.toString(actual)));
100 }
101 }
102
103
104 final int version = NB.decodeUInt16(scratch, 4);
105 if (version != 1)
106 throw new IOException(MessageFormat.format(
107 JGitText.get().unsupportedPackIndexVersion,
108 Integer.valueOf(version)));
109
110
111 final int opts = NB.decodeUInt16(scratch, 6);
112 if ((opts & OPT_FULL) == 0)
113 throw new IOException(MessageFormat.format(
114 JGitText.get().expectedGot, Integer.valueOf(OPT_FULL),
115 Integer.valueOf(opts)));
116
117
118 long numEntries = NB.decodeUInt32(scratch, 8);
119 if (numEntries > Integer.MAX_VALUE)
120 throw new IOException(JGitText.get().indexFileIsTooLargeForJgit);
121
122
123 this.packChecksum = new byte[20];
124 System.arraycopy(scratch, 12, packChecksum, 0, packChecksum.length);
125
126
127 SimpleDataInput dataInput = new SimpleDataInput(fd);
128 this.commits = readBitmap(dataInput);
129 this.trees = readBitmap(dataInput);
130 this.blobs = readBitmap(dataInput);
131 this.tags = readBitmap(dataInput);
132
133
134
135
136 StoredBitmap[] recentBitmaps = new StoredBitmap[MAX_XOR_OFFSET];
137 for (int i = 0; i < (int) numEntries; i++) {
138 IO.readFully(fd, scratch, 0, 6);
139 int nthObjectId = NB.decodeInt32(scratch, 0);
140 int xorOffset = scratch[4];
141 int flags = scratch[5];
142 EWAHCompressedBitmap bitmap = readBitmap(dataInput);
143
144 if (nthObjectId < 0)
145 throw new IOException(MessageFormat.format(
146 JGitText.get().invalidId, String.valueOf(nthObjectId)));
147 if (xorOffset < 0)
148 throw new IOException(MessageFormat.format(
149 JGitText.get().invalidId, String.valueOf(xorOffset)));
150 if (xorOffset > MAX_XOR_OFFSET)
151 throw new IOException(MessageFormat.format(
152 JGitText.get().expectedLessThanGot,
153 String.valueOf(MAX_XOR_OFFSET),
154 String.valueOf(xorOffset)));
155 if (xorOffset > i)
156 throw new IOException(MessageFormat.format(
157 JGitText.get().expectedLessThanGot, String.valueOf(i),
158 String.valueOf(xorOffset)));
159
160 ObjectId objectId = packIndex.getObjectId(nthObjectId);
161 StoredBitmap xorBitmap = null;
162 if (xorOffset > 0) {
163 int index = (i - xorOffset);
164 xorBitmap = recentBitmaps[index % recentBitmaps.length];
165 if (xorBitmap == null)
166 throw new IOException(MessageFormat.format(
167 JGitText.get().invalidId,
168 String.valueOf(xorOffset)));
169 }
170
171 StoredBitmap sb = new StoredBitmap(
172 objectId, bitmap, xorBitmap, flags);
173 bitmaps.add(sb);
174 recentBitmaps[i % recentBitmaps.length] = sb;
175 }
176 }
177
178
179 @Override
180 public int findPosition(AnyObjectId objectId) {
181 long offset = packIndex.findOffset(objectId);
182 if (offset == -1)
183 return -1;
184 return reverseIndex.findPostion(offset);
185 }
186
187
188 @Override
189 public ObjectId getObject(int position) throws IllegalArgumentException {
190 ObjectId objectId = reverseIndex.findObjectByPosition(position);
191 if (objectId == null)
192 throw new IllegalArgumentException();
193 return objectId;
194 }
195
196
197 @Override
198 public int getObjectCount() {
199 return (int) packIndex.getObjectCount();
200 }
201
202
203 @Override
204 public EWAHCompressedBitmap ofObjectType(
205 EWAHCompressedBitmap bitmap, int type) {
206 switch (type) {
207 case Constants.OBJ_BLOB:
208 return blobs.and(bitmap);
209 case Constants.OBJ_TREE:
210 return trees.and(bitmap);
211 case Constants.OBJ_COMMIT:
212 return commits.and(bitmap);
213 case Constants.OBJ_TAG:
214 return tags.and(bitmap);
215 }
216 throw new IllegalArgumentException();
217 }
218
219
220 @Override
221 public int getBitmapCount() {
222 return bitmaps.size();
223 }
224
225
226 @Override
227 public boolean equals(Object o) {
228
229 if (o instanceof PackBitmapIndexV1)
230 return getPackIndex() == ((PackBitmapIndexV1) o).getPackIndex();
231 return false;
232 }
233
234
235 @Override
236 public int hashCode() {
237 return getPackIndex().hashCode();
238 }
239
240 PackIndex getPackIndex() {
241 return packIndex;
242 }
243
244 private static EWAHCompressedBitmap readBitmap(DataInput dataInput)
245 throws IOException {
246 EWAHCompressedBitmap bitmap = new EWAHCompressedBitmap();
247 bitmap.deserialize(dataInput);
248 return bitmap;
249 }
250 }