View Javadoc
1   /*
2    * Copyright (C) 2012, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.internal.storage.file;
12  
13  import java.io.BufferedOutputStream;
14  import java.io.DataOutput;
15  import java.io.IOException;
16  import java.io.OutputStream;
17  import java.security.DigestOutputStream;
18  import java.text.MessageFormat;
19  
20  import org.eclipse.jgit.internal.JGitText;
21  import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder.StoredEntry;
22  import org.eclipse.jgit.lib.Constants;
23  
24  import com.googlecode.javaewah.EWAHCompressedBitmap;
25  
26  /**
27   * Creates the version 1 pack bitmap index files.
28   *
29   * @see PackBitmapIndexV1
30   */
31  public class PackBitmapIndexWriterV1 {
32  	private final DigestOutputStream out;
33  	private final DataOutput dataOutput;
34  
35  	/**
36  	 * Creates the version 1 pack bitmap index files.
37  	 *
38  	 * @param dst
39  	 *            the output stream to which the index will be written.
40  	 */
41  	public PackBitmapIndexWriterV1(final OutputStream dst) {
42  		out = new DigestOutputStream(dst instanceof BufferedOutputStream ? dst
43  				: new BufferedOutputStream(dst),
44  				Constants.newMessageDigest());
45  		dataOutput = new SimpleDataOutput(out);
46  	}
47  
48  	/**
49  	 * Write all object entries to the index stream.
50  	 * <p>
51  	 * After writing the stream passed to the factory is flushed but remains
52  	 * open. Callers are always responsible for closing the output stream.
53  	 *
54  	 * @param bitmaps
55  	 *            the index data for the bitmaps
56  	 * @param packDataChecksum
57  	 *            checksum signature of the entire pack data content. This is
58  	 *            traditionally the last 20 bytes of the pack file's own stream.
59  	 * @throws java.io.IOException
60  	 *             an error occurred while writing to the output stream, or this
61  	 *             index format cannot store the object data supplied.
62  	 */
63  	public void write(PackBitmapIndexBuilder bitmaps, byte[] packDataChecksum)
64  			throws IOException {
65  		if (bitmaps == null || packDataChecksum.length != 20)
66  			throw new IllegalStateException();
67  
68  		writeHeader(bitmaps.getOptions(), bitmaps.getBitmapCount(),
69  				packDataChecksum);
70  		writeBody(bitmaps);
71  		writeFooter();
72  
73  		out.flush();
74  	}
75  
76  	private void writeHeader(
77  			int options, int bitmapCount, byte[] packDataChecksum)
78  			throws IOException {
79  		out.write(PackBitmapIndexV1.MAGIC);
80  		dataOutput.writeShort(1);
81  		dataOutput.writeShort(options);
82  		dataOutput.writeInt(bitmapCount);
83  		out.write(packDataChecksum);
84  	}
85  
86  	private void writeBody(PackBitmapIndexBuilder bitmaps) throws IOException {
87  		writeBitmap(bitmaps.getCommits());
88  		writeBitmap(bitmaps.getTrees());
89  		writeBitmap(bitmaps.getBlobs());
90  		writeBitmap(bitmaps.getTags());
91  		writeBitmaps(bitmaps);
92  	}
93  
94  	private void writeBitmap(EWAHCompressedBitmap bitmap) throws IOException {
95  		bitmap.serialize(dataOutput);
96  	}
97  
98  	private void writeBitmaps(PackBitmapIndexBuilder bitmaps)
99  			throws IOException {
100 		int bitmapCount = 0;
101 		for (StoredEntry entry : bitmaps.getCompressedBitmaps()) {
102 			writeBitmapEntry(entry);
103 			bitmapCount++;
104 		}
105 
106 		int expectedBitmapCount = bitmaps.getBitmapCount();
107 		if (expectedBitmapCount != bitmapCount)
108 			throw new IOException(MessageFormat.format(
109 					JGitText.get().expectedGot,
110 					String.valueOf(expectedBitmapCount),
111 					String.valueOf(bitmapCount)));
112 	}
113 
114 	private void writeBitmapEntry(StoredEntry entry) throws IOException {
115 		// Write object, XOR offset, and bitmap
116 		dataOutput.writeInt((int) entry.getObjectId());
117 		out.write(entry.getXorOffset());
118 		out.write(entry.getFlags());
119 		writeBitmap(entry.getBitmap());
120 	}
121 
122 	private void writeFooter() throws IOException {
123 		out.on(false);
124 		out.write(out.getMessageDigest().digest());
125 	}
126 }