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 @Override
179 public int findPosition(AnyObjectId objectId) {
180 long offset = packIndex.findOffset(objectId);
181 if (offset == -1)
182 return -1;
183 return reverseIndex.findPostion(offset);
184 }
185
186 @Override
187 public ObjectId getObject(int position) throws IllegalArgumentException {
188 ObjectId objectId = reverseIndex.findObjectByPosition(position);
189 if (objectId == null)
190 throw new IllegalArgumentException();
191 return objectId;
192 }
193
194 @Override
195 public int getObjectCount() {
196 return (int) packIndex.getObjectCount();
197 }
198
199 @Override
200 public EWAHCompressedBitmap ofObjectType(
201 EWAHCompressedBitmap bitmap, int type) {
202 switch (type) {
203 case Constants.OBJ_BLOB:
204 return blobs.and(bitmap);
205 case Constants.OBJ_TREE:
206 return trees.and(bitmap);
207 case Constants.OBJ_COMMIT:
208 return commits.and(bitmap);
209 case Constants.OBJ_TAG:
210 return tags.and(bitmap);
211 }
212 throw new IllegalArgumentException();
213 }
214
215 @Override
216 public int getBitmapCount() {
217 return bitmaps.size();
218 }
219
220 @Override
221 public boolean equals(Object o) {
222
223 if (o instanceof PackBitmapIndexV1)
224 return getPackIndex() == ((PackBitmapIndexV1) o).getPackIndex();
225 return false;
226 }
227
228 @Override
229 public int hashCode() {
230 return getPackIndex().hashCode();
231 }
232
233 PackIndex getPackIndex() {
234 return packIndex;
235 }
236
237 private static EWAHCompressedBitmap readBitmap(DataInput dataInput)
238 throws IOException {
239 EWAHCompressedBitmap bitmap = new EWAHCompressedBitmap();
240 bitmap.deserialize(dataInput);
241 return bitmap;
242 }
243 }