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