View Javadoc
1   /*
2    * Copyright (C) 2008-2011, Google Inc.
3    * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5    * and other copyright owners as documented in the project's IP log.
6    *
7    * This program and the accompanying materials are made available
8    * under the terms of the Eclipse Distribution License v1.0 which
9    * accompanies this distribution, is reproduced below, and is
10   * available at http://www.eclipse.org/org/documents/edl-v10.php
11   *
12   * All rights reserved.
13   *
14   * Redistribution and use in source and binary forms, with or
15   * without modification, are permitted provided that the following
16   * conditions are met:
17   *
18   * - Redistributions of source code must retain the above copyright
19   *   notice, this list of conditions and the following disclaimer.
20   *
21   * - Redistributions in binary form must reproduce the above
22   *   copyright notice, this list of conditions and the following
23   *   disclaimer in the documentation and/or other materials provided
24   *   with the distribution.
25   *
26   * - Neither the name of the Eclipse Foundation, Inc. nor the
27   *   names of its contributors may be used to endorse or promote
28   *   products derived from this software without specific prior
29   *   written permission.
30   *
31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44   */
45  
46  package org.eclipse.jgit.transport;
47  
48  import java.io.EOFException;
49  import java.io.IOException;
50  import java.io.InputStream;
51  import java.security.MessageDigest;
52  import java.text.MessageFormat;
53  import java.util.ArrayList;
54  import java.util.Arrays;
55  import java.util.Comparator;
56  import java.util.List;
57  import java.util.concurrent.TimeUnit;
58  import java.util.zip.DataFormatException;
59  import java.util.zip.Inflater;
60  
61  import org.eclipse.jgit.errors.CorruptObjectException;
62  import org.eclipse.jgit.errors.MissingObjectException;
63  import org.eclipse.jgit.errors.TooLargeObjectInPackException;
64  import org.eclipse.jgit.internal.JGitText;
65  import org.eclipse.jgit.internal.storage.file.PackLock;
66  import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
67  import org.eclipse.jgit.lib.AnyObjectId;
68  import org.eclipse.jgit.lib.BatchingProgressMonitor;
69  import org.eclipse.jgit.lib.Constants;
70  import org.eclipse.jgit.lib.InflaterCache;
71  import org.eclipse.jgit.lib.MutableObjectId;
72  import org.eclipse.jgit.lib.NullProgressMonitor;
73  import org.eclipse.jgit.lib.ObjectChecker;
74  import org.eclipse.jgit.lib.ObjectDatabase;
75  import org.eclipse.jgit.lib.ObjectId;
76  import org.eclipse.jgit.lib.ObjectIdOwnerMap;
77  import org.eclipse.jgit.lib.ObjectIdSubclassMap;
78  import org.eclipse.jgit.lib.ObjectInserter;
79  import org.eclipse.jgit.lib.ObjectLoader;
80  import org.eclipse.jgit.lib.ObjectReader;
81  import org.eclipse.jgit.lib.ObjectStream;
82  import org.eclipse.jgit.lib.ProgressMonitor;
83  import org.eclipse.jgit.util.BlockList;
84  import org.eclipse.jgit.util.IO;
85  import org.eclipse.jgit.util.NB;
86  
87  /**
88   * Parses a pack stream and imports it for an {@link ObjectInserter}.
89   * <p>
90   * Applications can acquire an instance of a parser from ObjectInserter's
91   * {@link ObjectInserter#newPackParser(InputStream)} method.
92   * <p>
93   * Implementations of {@link ObjectInserter} should subclass this type and
94   * provide their own logic for the various {@code on*()} event methods declared
95   * to be abstract.
96   */
97  public abstract class PackParser {
98  	/** Size of the internal stream buffer. */
99  	private static final int BUFFER_SIZE = 8192;
100 
101 	/** Location data is being obtained from. */
102 	public static enum Source {
103 		/** Data is read from the incoming stream. */
104 		INPUT,
105 
106 		/** Data is read back from the database's buffers. */
107 		DATABASE;
108 	}
109 
110 	/** Object database used for loading existing objects. */
111 	private final ObjectDatabase objectDatabase;
112 
113 	private InflaterStream inflater;
114 
115 	private byte[] tempBuffer;
116 
117 	private byte[] hdrBuf;
118 
119 	private final MessageDigest objectDigest;
120 
121 	private final MutableObjectId tempObjectId;
122 
123 	private InputStream in;
124 
125 	private byte[] buf;
126 
127 	/** Position in the input stream of {@code buf[0]}. */
128 	private long bBase;
129 
130 	private int bOffset;
131 
132 	private int bAvail;
133 
134 	private ObjectChecker objCheck;
135 
136 	private boolean allowThin;
137 
138 	private boolean needBaseObjectIds;
139 
140 	private boolean checkEofAfterPackFooter;
141 
142 	private boolean expectDataAfterPackFooter;
143 
144 	private long objectCount;
145 
146 	private PackedObjectInfo[] entries;
147 
148 	/**
149 	 * Every object contained within the incoming pack.
150 	 * <p>
151 	 * This is a subset of {@link #entries}, as thin packs can add additional
152 	 * objects to {@code entries} by copying already existing objects from the
153 	 * repository onto the end of the thin pack to make it self-contained.
154 	 */
155 	private ObjectIdSubclassMap<ObjectId> newObjectIds;
156 
157 	private int deltaCount;
158 
159 	private int entryCount;
160 
161 	private ObjectIdOwnerMap<DeltaChain> baseById;
162 
163 	/**
164 	 * Objects referenced by their name from deltas, that aren't in this pack.
165 	 * <p>
166 	 * This is the set of objects that were copied onto the end of this pack to
167 	 * make it complete. These objects were not transmitted by the remote peer,
168 	 * but instead were assumed to already exist in the local repository.
169 	 */
170 	private ObjectIdSubclassMap<ObjectId> baseObjectIds;
171 
172 	private LongMap<UnresolvedDelta> baseByPos;
173 
174 	/** Blobs whose contents need to be double-checked after indexing. */
175 	private BlockList<PackedObjectInfo> deferredCheckBlobs;
176 
177 	private MessageDigest packDigest;
178 
179 	private ObjectReader readCurs;
180 
181 	/** Message to protect the pack data from garbage collection. */
182 	private String lockMessage;
183 
184 	/** Git object size limit */
185 	private long maxObjectSizeLimit;
186 
187 	/**
188 	 * Initialize a pack parser.
189 	 *
190 	 * @param odb
191 	 *            database the parser will write its objects into.
192 	 * @param src
193 	 *            the stream the parser will read.
194 	 */
195 	protected PackParser(final ObjectDatabase odb, final InputStream src) {
196 		objectDatabase = odb.newCachedDatabase();
197 		in = src;
198 
199 		inflater = new InflaterStream();
200 		readCurs = objectDatabase.newReader();
201 		buf = new byte[BUFFER_SIZE];
202 		tempBuffer = new byte[BUFFER_SIZE];
203 		hdrBuf = new byte[64];
204 		objectDigest = Constants.newMessageDigest();
205 		tempObjectId = new MutableObjectId();
206 		packDigest = Constants.newMessageDigest();
207 	}
208 
209 	/** @return true if a thin pack (missing base objects) is permitted. */
210 	public boolean isAllowThin() {
211 		return allowThin;
212 	}
213 
214 	/**
215 	 * Configure this index pack instance to allow a thin pack.
216 	 * <p>
217 	 * Thin packs are sometimes used during network transfers to allow a delta
218 	 * to be sent without a base object. Such packs are not permitted on disk.
219 	 *
220 	 * @param allow
221 	 *            true to enable a thin pack.
222 	 */
223 	public void setAllowThin(final boolean allow) {
224 		allowThin = allow;
225 	}
226 
227 	/**
228 	 * Configure this index pack instance to keep track of new objects.
229 	 * <p>
230 	 * By default an index pack doesn't save the new objects that were created
231 	 * when it was instantiated. Setting this flag to {@code true} allows the
232 	 * caller to use {@link #getNewObjectIds()} to retrieve that list.
233 	 *
234 	 * @param b
235 	 *            {@code true} to enable keeping track of new objects.
236 	 */
237 	public void setNeedNewObjectIds(boolean b) {
238 		if (b)
239 			newObjectIds = new ObjectIdSubclassMap<ObjectId>();
240 		else
241 			newObjectIds = null;
242 	}
243 
244 	private boolean needNewObjectIds() {
245 		return newObjectIds != null;
246 	}
247 
248 	/**
249 	 * Configure this index pack instance to keep track of the objects assumed
250 	 * for delta bases.
251 	 * <p>
252 	 * By default an index pack doesn't save the objects that were used as delta
253 	 * bases. Setting this flag to {@code true} will allow the caller to use
254 	 * {@link #getBaseObjectIds()} to retrieve that list.
255 	 *
256 	 * @param b
257 	 *            {@code true} to enable keeping track of delta bases.
258 	 */
259 	public void setNeedBaseObjectIds(boolean b) {
260 		this.needBaseObjectIds = b;
261 	}
262 
263 	/** @return true if the EOF should be read from the input after the footer. */
264 	public boolean isCheckEofAfterPackFooter() {
265 		return checkEofAfterPackFooter;
266 	}
267 
268 	/**
269 	 * Ensure EOF is read from the input stream after the footer.
270 	 *
271 	 * @param b
272 	 *            true if the EOF should be read; false if it is not checked.
273 	 */
274 	public void setCheckEofAfterPackFooter(boolean b) {
275 		checkEofAfterPackFooter = b;
276 	}
277 
278 	/** @return true if there is data expected after the pack footer. */
279 	public boolean isExpectDataAfterPackFooter() {
280 		return expectDataAfterPackFooter;
281 	}
282 
283 	/**
284 	 * @param e
285 	 *            true if there is additional data in InputStream after pack.
286 	 *            This requires the InputStream to support the mark and reset
287 	 *            functions.
288 	 */
289 	public void setExpectDataAfterPackFooter(boolean e) {
290 		expectDataAfterPackFooter = e;
291 	}
292 
293 	/** @return the new objects that were sent by the user */
294 	public ObjectIdSubclassMap<ObjectId> getNewObjectIds() {
295 		if (newObjectIds != null)
296 			return newObjectIds;
297 		return new ObjectIdSubclassMap<ObjectId>();
298 	}
299 
300 	/** @return set of objects the incoming pack assumed for delta purposes */
301 	public ObjectIdSubclassMap<ObjectId> getBaseObjectIds() {
302 		if (baseObjectIds != null)
303 			return baseObjectIds;
304 		return new ObjectIdSubclassMap<ObjectId>();
305 	}
306 
307 	/**
308 	 * Configure the checker used to validate received objects.
309 	 * <p>
310 	 * Usually object checking isn't necessary, as Git implementations only
311 	 * create valid objects in pack files. However, additional checking may be
312 	 * useful if processing data from an untrusted source.
313 	 *
314 	 * @param oc
315 	 *            the checker instance; null to disable object checking.
316 	 */
317 	public void setObjectChecker(final ObjectChecker oc) {
318 		objCheck = oc;
319 	}
320 
321 	/**
322 	 * Configure the checker used to validate received objects.
323 	 * <p>
324 	 * Usually object checking isn't necessary, as Git implementations only
325 	 * create valid objects in pack files. However, additional checking may be
326 	 * useful if processing data from an untrusted source.
327 	 * <p>
328 	 * This is shorthand for:
329 	 *
330 	 * <pre>
331 	 * setObjectChecker(on ? new ObjectChecker() : null);
332 	 * </pre>
333 	 *
334 	 * @param on
335 	 *            true to enable the default checker; false to disable it.
336 	 */
337 	public void setObjectChecking(final boolean on) {
338 		setObjectChecker(on ? new ObjectChecker() : null);
339 	}
340 
341 	/** @return the message to record with the pack lock. */
342 	public String getLockMessage() {
343 		return lockMessage;
344 	}
345 
346 	/**
347 	 * Set the lock message for the incoming pack data.
348 	 *
349 	 * @param msg
350 	 *            if not null, the message to associate with the incoming data
351 	 *            while it is locked to prevent garbage collection.
352 	 */
353 	public void setLockMessage(String msg) {
354 		lockMessage = msg;
355 	}
356 
357 	/**
358 	 * Set the maximum allowed Git object size.
359 	 * <p>
360 	 * If an object is larger than the given size the pack-parsing will throw an
361 	 * exception aborting the parsing.
362 	 *
363 	 * @param limit
364 	 *            the Git object size limit. If zero then there is not limit.
365 	 */
366 	public void setMaxObjectSizeLimit(long limit) {
367 		maxObjectSizeLimit = limit;
368 	}
369 
370 	/**
371 	 * Get the number of objects in the stream.
372 	 * <p>
373 	 * The object count is only available after {@link #parse(ProgressMonitor)}
374 	 * has returned. The count may have been increased if the stream was a thin
375 	 * pack, and missing bases objects were appending onto it by the subclass.
376 	 *
377 	 * @return number of objects parsed out of the stream.
378 	 */
379 	public int getObjectCount() {
380 		return entryCount;
381 	}
382 
383 	/***
384 	 * Get the information about the requested object.
385 	 * <p>
386 	 * The object information is only available after
387 	 * {@link #parse(ProgressMonitor)} has returned.
388 	 *
389 	 * @param nth
390 	 *            index of the object in the stream. Must be between 0 and
391 	 *            {@link #getObjectCount()}-1.
392 	 * @return the object information.
393 	 */
394 	public PackedObjectInfo getObject(int nth) {
395 		return entries[nth];
396 	}
397 
398 	/**
399 	 * Get all of the objects, sorted by their name.
400 	 * <p>
401 	 * The object information is only available after
402 	 * {@link #parse(ProgressMonitor)} has returned.
403 	 * <p>
404 	 * To maintain lower memory usage and good runtime performance, this method
405 	 * sorts the objects in-place and therefore impacts the ordering presented
406 	 * by {@link #getObject(int)}.
407 	 *
408 	 * @param cmp
409 	 *            comparison function, if null objects are stored by ObjectId.
410 	 * @return sorted list of objects in this pack stream.
411 	 */
412 	public List<PackedObjectInfo> getSortedObjectList(
413 			Comparator<PackedObjectInfo> cmp) {
414 		Arrays.sort(entries, 0, entryCount, cmp);
415 		List<PackedObjectInfo> list = Arrays.asList(entries);
416 		if (entryCount < entries.length)
417 			list = list.subList(0, entryCount);
418 		return list;
419 	}
420 
421 	/**
422 	 * Get the size of the parsed pack.
423 	 *
424 	 * This will also include the pack index size if an index was created. This
425 	 * method should only be called after pack parsing is finished.
426 	 *
427 	 * @return the pack size (including the index size) or -1 if the size cannot
428 	 *         be determined
429 	 * @since 3.3
430 	 */
431 	public long getPackSize() {
432 		return -1;
433 	}
434 
435 	/**
436 	 * Parse the pack stream.
437 	 *
438 	 * @param progress
439 	 *            callback to provide progress feedback during parsing. If null,
440 	 *            {@link NullProgressMonitor} will be used.
441 	 * @return the pack lock, if one was requested by setting
442 	 *         {@link #setLockMessage(String)}.
443 	 * @throws IOException
444 	 *             the stream is malformed, or contains corrupt objects.
445 	 * @since 3.0
446 	 */
447 	public final PackLock parse(ProgressMonitor progress) throws IOException {
448 		return parse(progress, progress);
449 	}
450 
451 	/**
452 	 * Parse the pack stream.
453 	 *
454 	 * @param receiving
455 	 *            receives progress feedback during the initial receiving
456 	 *            objects phase. If null, {@link NullProgressMonitor} will be
457 	 *            used.
458 	 * @param resolving
459 	 *            receives progress feedback during the resolving objects phase.
460 	 * @return the pack lock, if one was requested by setting
461 	 *         {@link #setLockMessage(String)}.
462 	 * @throws IOException
463 	 *             the stream is malformed, or contains corrupt objects.
464 	 * @since 3.0
465 	 */
466 	public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
467 			throws IOException {
468 		if (receiving == null)
469 			receiving = NullProgressMonitor.INSTANCE;
470 		if (resolving == null)
471 			resolving = NullProgressMonitor.INSTANCE;
472 
473 		if (receiving == resolving)
474 			receiving.start(2 /* tasks */);
475 		try {
476 			readPackHeader();
477 
478 			entries = new PackedObjectInfo[(int) objectCount];
479 			baseById = new ObjectIdOwnerMap<DeltaChain>();
480 			baseByPos = new LongMap<UnresolvedDelta>();
481 			deferredCheckBlobs = new BlockList<PackedObjectInfo>();
482 
483 			receiving.beginTask(JGitText.get().receivingObjects,
484 					(int) objectCount);
485 			try {
486 				for (int done = 0; done < objectCount; done++) {
487 					indexOneObject();
488 					receiving.update(1);
489 					if (receiving.isCancelled())
490 						throw new IOException(JGitText.get().downloadCancelled);
491 				}
492 				readPackFooter();
493 				endInput();
494 			} finally {
495 				receiving.endTask();
496 			}
497 
498 			if (!deferredCheckBlobs.isEmpty())
499 				doDeferredCheckBlobs();
500 			if (deltaCount > 0) {
501 				if (resolving instanceof BatchingProgressMonitor) {
502 					((BatchingProgressMonitor) resolving).setDelayStart(
503 							1000,
504 							TimeUnit.MILLISECONDS);
505 				}
506 				resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
507 				resolveDeltas(resolving);
508 				if (entryCount < objectCount) {
509 					if (!isAllowThin()) {
510 						throw new IOException(MessageFormat.format(
511 								JGitText.get().packHasUnresolvedDeltas,
512 								Long.valueOf(objectCount - entryCount)));
513 					}
514 
515 					resolveDeltasWithExternalBases(resolving);
516 
517 					if (entryCount < objectCount) {
518 						throw new IOException(MessageFormat.format(
519 								JGitText.get().packHasUnresolvedDeltas,
520 								Long.valueOf(objectCount - entryCount)));
521 					}
522 				}
523 				resolving.endTask();
524 			}
525 
526 			packDigest = null;
527 			baseById = null;
528 			baseByPos = null;
529 		} finally {
530 			try {
531 				if (readCurs != null)
532 					readCurs.close();
533 			} finally {
534 				readCurs = null;
535 			}
536 
537 			try {
538 				inflater.release();
539 			} finally {
540 				inflater = null;
541 			}
542 		}
543 		return null; // By default there is no locking.
544 	}
545 
546 	private void resolveDeltas(final ProgressMonitor progress)
547 			throws IOException {
548 		final int last = entryCount;
549 		for (int i = 0; i < last; i++) {
550 			resolveDeltas(entries[i], progress);
551 			if (progress.isCancelled())
552 				throw new IOException(
553 						JGitText.get().downloadCancelledDuringIndexing);
554 		}
555 	}
556 
557 	private void resolveDeltas(final PackedObjectInfo oe,
558 			ProgressMonitor progress) throws IOException {
559 		UnresolvedDelta children = firstChildOf(oe);
560 		if (children == null)
561 			return;
562 
563 		DeltaVisit visit = new DeltaVisit();
564 		visit.nextChild = children;
565 
566 		ObjectTypeAndSize info = openDatabase(oe, new ObjectTypeAndSize());
567 		switch (info.type) {
568 		case Constants.OBJ_COMMIT:
569 		case Constants.OBJ_TREE:
570 		case Constants.OBJ_BLOB:
571 		case Constants.OBJ_TAG:
572 			visit.data = inflateAndReturn(Source.DATABASE, info.size);
573 			visit.id = oe;
574 			break;
575 		default:
576 			throw new IOException(MessageFormat.format(
577 					JGitText.get().unknownObjectType,
578 					Integer.valueOf(info.type)));
579 		}
580 
581 		if (!checkCRC(oe.getCRC())) {
582 			throw new IOException(MessageFormat.format(
583 					JGitText.get().corruptionDetectedReReadingAt,
584 					Long.valueOf(oe.getOffset())));
585 		}
586 
587 		resolveDeltas(visit.next(), info.type, info, progress);
588 	}
589 
590 	private void resolveDeltas(DeltaVisit visit, final int type,
591 			ObjectTypeAndSize info, ProgressMonitor progress)
592 			throws IOException {
593 		do {
594 			progress.update(1);
595 			info = openDatabase(visit.delta, info);
596 			switch (info.type) {
597 			case Constants.OBJ_OFS_DELTA:
598 			case Constants.OBJ_REF_DELTA:
599 				break;
600 
601 			default:
602 				throw new IOException(MessageFormat.format(
603 						JGitText.get().unknownObjectType,
604 						Integer.valueOf(info.type)));
605 			}
606 
607 			byte[] delta = inflateAndReturn(Source.DATABASE, info.size);
608 			checkIfTooLarge(type, BinaryDelta.getResultSize(delta));
609 
610 			visit.data = BinaryDelta.apply(visit.parent.data, delta);
611 			delta = null;
612 
613 			if (!checkCRC(visit.delta.crc))
614 				throw new IOException(MessageFormat.format(
615 						JGitText.get().corruptionDetectedReReadingAt,
616 						Long.valueOf(visit.delta.position)));
617 
618 			objectDigest.update(Constants.encodedTypeString(type));
619 			objectDigest.update((byte) ' ');
620 			objectDigest.update(Constants.encodeASCII(visit.data.length));
621 			objectDigest.update((byte) 0);
622 			objectDigest.update(visit.data);
623 			tempObjectId.fromRaw(objectDigest.digest(), 0);
624 
625 			verifySafeObject(tempObjectId, type, visit.data);
626 
627 			PackedObjectInfo oe;
628 			oe = newInfo(tempObjectId, visit.delta, visit.parent.id);
629 			oe.setOffset(visit.delta.position);
630 			onInflatedObjectData(oe, type, visit.data);
631 			addObjectAndTrack(oe);
632 			visit.id = oe;
633 
634 			visit.nextChild = firstChildOf(oe);
635 			visit = visit.next();
636 		} while (visit != null);
637 	}
638 
639 	private final void checkIfTooLarge(int typeCode, long size)
640 			throws IOException {
641 		if (0 < maxObjectSizeLimit && maxObjectSizeLimit < size)
642 			switch (typeCode) {
643 			case Constants.OBJ_COMMIT:
644 			case Constants.OBJ_TREE:
645 			case Constants.OBJ_BLOB:
646 			case Constants.OBJ_TAG:
647 				throw new TooLargeObjectInPackException(size, maxObjectSizeLimit);
648 
649 			case Constants.OBJ_OFS_DELTA:
650 			case Constants.OBJ_REF_DELTA:
651 				throw new TooLargeObjectInPackException(maxObjectSizeLimit);
652 
653 			default:
654 				throw new IOException(MessageFormat.format(
655 						JGitText.get().unknownObjectType,
656 						Integer.valueOf(typeCode)));
657 			}
658 	}
659 
660 	/**
661 	 * Read the header of the current object.
662 	 * <p>
663 	 * After the header has been parsed, this method automatically invokes
664 	 * {@link #onObjectHeader(Source, byte[], int, int)} to allow the
665 	 * implementation to update its internal checksums for the bytes read.
666 	 * <p>
667 	 * When this method returns the database will be positioned on the first
668 	 * byte of the deflated data stream.
669 	 *
670 	 * @param info
671 	 *            the info object to populate.
672 	 * @return {@code info}, after populating.
673 	 * @throws IOException
674 	 *             the size cannot be read.
675 	 */
676 	protected ObjectTypeAndSize readObjectHeader(ObjectTypeAndSize info)
677 			throws IOException {
678 		int hdrPtr = 0;
679 		int c = readFrom(Source.DATABASE);
680 		hdrBuf[hdrPtr++] = (byte) c;
681 
682 		info.type = (c >> 4) & 7;
683 		long sz = c & 15;
684 		int shift = 4;
685 		while ((c & 0x80) != 0) {
686 			c = readFrom(Source.DATABASE);
687 			hdrBuf[hdrPtr++] = (byte) c;
688 			sz += ((long) (c & 0x7f)) << shift;
689 			shift += 7;
690 		}
691 		info.size = sz;
692 
693 		switch (info.type) {
694 		case Constants.OBJ_COMMIT:
695 		case Constants.OBJ_TREE:
696 		case Constants.OBJ_BLOB:
697 		case Constants.OBJ_TAG:
698 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
699 			break;
700 
701 		case Constants.OBJ_OFS_DELTA:
702 			c = readFrom(Source.DATABASE);
703 			hdrBuf[hdrPtr++] = (byte) c;
704 			while ((c & 128) != 0) {
705 				c = readFrom(Source.DATABASE);
706 				hdrBuf[hdrPtr++] = (byte) c;
707 			}
708 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
709 			break;
710 
711 		case Constants.OBJ_REF_DELTA:
712 			System.arraycopy(buf, fill(Source.DATABASE, 20), hdrBuf, hdrPtr, 20);
713 			hdrPtr += 20;
714 			use(20);
715 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
716 			break;
717 
718 		default:
719 			throw new IOException(MessageFormat.format(
720 					JGitText.get().unknownObjectType,
721 					Integer.valueOf(info.type)));
722 		}
723 		return info;
724 	}
725 
726 	private UnresolvedDelta removeBaseById(final AnyObjectId id) {
727 		final DeltaChain d = baseById.get(id);
728 		return d != null ? d.remove() : null;
729 	}
730 
731 	private static UnresolvedDelta reverse(UnresolvedDelta c) {
732 		UnresolvedDelta tail = null;
733 		while (c != null) {
734 			final UnresolvedDelta n = c.next;
735 			c.next = tail;
736 			tail = c;
737 			c = n;
738 		}
739 		return tail;
740 	}
741 
742 	private UnresolvedDelta firstChildOf(PackedObjectInfo oe) {
743 		UnresolvedDelta a = reverse(removeBaseById(oe));
744 		UnresolvedDelta b = reverse(baseByPos.remove(oe.getOffset()));
745 
746 		if (a == null)
747 			return b;
748 		if (b == null)
749 			return a;
750 
751 		UnresolvedDelta first = null;
752 		UnresolvedDelta last = null;
753 		while (a != null || b != null) {
754 			UnresolvedDelta curr;
755 			if (b == null || (a != null && a.position < b.position)) {
756 				curr = a;
757 				a = a.next;
758 			} else {
759 				curr = b;
760 				b = b.next;
761 			}
762 			if (last != null)
763 				last.next = curr;
764 			else
765 				first = curr;
766 			last = curr;
767 			curr.next = null;
768 		}
769 		return first;
770 	}
771 
772 	private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
773 			throws IOException {
774 		growEntries(baseById.size());
775 
776 		if (needBaseObjectIds)
777 			baseObjectIds = new ObjectIdSubclassMap<ObjectId>();
778 
779 		final List<DeltaChain> missing = new ArrayList<DeltaChain>(64);
780 		for (final DeltaChain baseId : baseById) {
781 			if (baseId.head == null)
782 				continue;
783 
784 			if (needBaseObjectIds)
785 				baseObjectIds.add(baseId);
786 
787 			final ObjectLoader ldr;
788 			try {
789 				ldr = readCurs.open(baseId);
790 			} catch (MissingObjectException notFound) {
791 				missing.add(baseId);
792 				continue;
793 			}
794 
795 			final DeltaVisit visit = new DeltaVisit();
796 			visit.data = ldr.getCachedBytes(Integer.MAX_VALUE);
797 			visit.id = baseId;
798 			final int typeCode = ldr.getType();
799 			final PackedObjectInfo oe = newInfo(baseId, null, null);
800 
801 			if (onAppendBase(typeCode, visit.data, oe))
802 				entries[entryCount++] = oe;
803 
804 			visit.nextChild = firstChildOf(oe);
805 			resolveDeltas(visit.next(), typeCode,
806 					new ObjectTypeAndSize(), progress);
807 
808 			if (progress.isCancelled())
809 				throw new IOException(
810 						JGitText.get().downloadCancelledDuringIndexing);
811 		}
812 
813 		for (final DeltaChain base : missing) {
814 			if (base.head != null)
815 				throw new MissingObjectException(base, "delta base"); //$NON-NLS-1$
816 		}
817 
818 		onEndThinPack();
819 	}
820 
821 	private void growEntries(int extraObjects) {
822 		final PackedObjectInfo[] ne;
823 
824 		ne = new PackedObjectInfo[(int) objectCount + extraObjects];
825 		System.arraycopy(entries, 0, ne, 0, entryCount);
826 		entries = ne;
827 	}
828 
829 	private void readPackHeader() throws IOException {
830 		if (expectDataAfterPackFooter) {
831 			if (!in.markSupported())
832 				throw new IOException(
833 						JGitText.get().inputStreamMustSupportMark);
834 			in.mark(buf.length);
835 		}
836 
837 		final int hdrln = Constants.PACK_SIGNATURE.length + 4 + 4;
838 		final int p = fill(Source.INPUT, hdrln);
839 		for (int k = 0; k < Constants.PACK_SIGNATURE.length; k++)
840 			if (buf[p + k] != Constants.PACK_SIGNATURE[k])
841 				throw new IOException(JGitText.get().notAPACKFile);
842 
843 		final long vers = NB.decodeUInt32(buf, p + 4);
844 		if (vers != 2 && vers != 3)
845 			throw new IOException(MessageFormat.format(
846 					JGitText.get().unsupportedPackVersion, Long.valueOf(vers)));
847 		objectCount = NB.decodeUInt32(buf, p + 8);
848 		use(hdrln);
849 
850 		onPackHeader(objectCount);
851 	}
852 
853 	private void readPackFooter() throws IOException {
854 		sync();
855 		final byte[] actHash = packDigest.digest();
856 
857 		final int c = fill(Source.INPUT, 20);
858 		final byte[] srcHash = new byte[20];
859 		System.arraycopy(buf, c, srcHash, 0, 20);
860 		use(20);
861 
862 		if (bAvail != 0 && !expectDataAfterPackFooter)
863 			throw new CorruptObjectException(MessageFormat.format(
864 					JGitText.get().expectedEOFReceived,
865 					"\\x" + Integer.toHexString(buf[bOffset] & 0xff))); //$NON-NLS-1$
866 		if (isCheckEofAfterPackFooter()) {
867 			int eof = in.read();
868 			if (0 <= eof)
869 				throw new CorruptObjectException(MessageFormat.format(
870 						JGitText.get().expectedEOFReceived,
871 						"\\x" + Integer.toHexString(eof))); //$NON-NLS-1$
872 		} else if (bAvail > 0 && expectDataAfterPackFooter) {
873 			in.reset();
874 			IO.skipFully(in, bOffset);
875 		}
876 
877 		if (!Arrays.equals(actHash, srcHash))
878 			throw new CorruptObjectException(
879 					JGitText.get().corruptObjectPackfileChecksumIncorrect);
880 
881 		onPackFooter(srcHash);
882 	}
883 
884 	// Cleanup all resources associated with our input parsing.
885 	private void endInput() {
886 		in = null;
887 	}
888 
889 	// Read one entire object or delta from the input.
890 	private void indexOneObject() throws IOException {
891 		final long streamPosition = streamPosition();
892 
893 		int hdrPtr = 0;
894 		int c = readFrom(Source.INPUT);
895 		hdrBuf[hdrPtr++] = (byte) c;
896 
897 		final int typeCode = (c >> 4) & 7;
898 		long sz = c & 15;
899 		int shift = 4;
900 		while ((c & 0x80) != 0) {
901 			c = readFrom(Source.INPUT);
902 			hdrBuf[hdrPtr++] = (byte) c;
903 			sz += ((long) (c & 0x7f)) << shift;
904 			shift += 7;
905 		}
906 
907 		checkIfTooLarge(typeCode, sz);
908 
909 		switch (typeCode) {
910 		case Constants.OBJ_COMMIT:
911 		case Constants.OBJ_TREE:
912 		case Constants.OBJ_BLOB:
913 		case Constants.OBJ_TAG:
914 			onBeginWholeObject(streamPosition, typeCode, sz);
915 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
916 			whole(streamPosition, typeCode, sz);
917 			break;
918 
919 		case Constants.OBJ_OFS_DELTA: {
920 			c = readFrom(Source.INPUT);
921 			hdrBuf[hdrPtr++] = (byte) c;
922 			long ofs = c & 127;
923 			while ((c & 128) != 0) {
924 				ofs += 1;
925 				c = readFrom(Source.INPUT);
926 				hdrBuf[hdrPtr++] = (byte) c;
927 				ofs <<= 7;
928 				ofs += (c & 127);
929 			}
930 			final long base = streamPosition - ofs;
931 			onBeginOfsDelta(streamPosition, base, sz);
932 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
933 			inflateAndSkip(Source.INPUT, sz);
934 			UnresolvedDelta n = onEndDelta();
935 			n.position = streamPosition;
936 			n.next = baseByPos.put(base, n);
937 			deltaCount++;
938 			break;
939 		}
940 
941 		case Constants.OBJ_REF_DELTA: {
942 			c = fill(Source.INPUT, 20);
943 			final ObjectId base = ObjectId.fromRaw(buf, c);
944 			System.arraycopy(buf, c, hdrBuf, hdrPtr, 20);
945 			hdrPtr += 20;
946 			use(20);
947 			DeltaChain r = baseById.get(base);
948 			if (r == null) {
949 				r = new DeltaChain(base);
950 				baseById.add(r);
951 			}
952 			onBeginRefDelta(streamPosition, base, sz);
953 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
954 			inflateAndSkip(Source.INPUT, sz);
955 			UnresolvedDelta n = onEndDelta();
956 			n.position = streamPosition;
957 			r.add(n);
958 			deltaCount++;
959 			break;
960 		}
961 
962 		default:
963 			throw new IOException(
964 					MessageFormat.format(JGitText.get().unknownObjectType,
965 							Integer.valueOf(typeCode)));
966 		}
967 	}
968 
969 	private void whole(final long pos, final int type, final long sz)
970 			throws IOException {
971 		objectDigest.update(Constants.encodedTypeString(type));
972 		objectDigest.update((byte) ' ');
973 		objectDigest.update(Constants.encodeASCII(sz));
974 		objectDigest.update((byte) 0);
975 
976 		final byte[] data;
977 		boolean checkContentLater = false;
978 		if (type == Constants.OBJ_BLOB) {
979 			byte[] readBuffer = buffer();
980 			InputStream inf = inflate(Source.INPUT, sz);
981 			long cnt = 0;
982 			while (cnt < sz) {
983 				int r = inf.read(readBuffer);
984 				if (r <= 0)
985 					break;
986 				objectDigest.update(readBuffer, 0, r);
987 				cnt += r;
988 			}
989 			inf.close();
990 			tempObjectId.fromRaw(objectDigest.digest(), 0);
991 			checkContentLater = readCurs.has(tempObjectId);
992 			data = null;
993 
994 		} else {
995 			data = inflateAndReturn(Source.INPUT, sz);
996 			objectDigest.update(data);
997 			tempObjectId.fromRaw(objectDigest.digest(), 0);
998 			verifySafeObject(tempObjectId, type, data);
999 		}
1000 
1001 		PackedObjectInfo obj = newInfo(tempObjectId, null, null);
1002 		obj.setOffset(pos);
1003 		onEndWholeObject(obj);
1004 		if (data != null)
1005 			onInflatedObjectData(obj, type, data);
1006 		addObjectAndTrack(obj);
1007 		if (checkContentLater)
1008 			deferredCheckBlobs.add(obj);
1009 	}
1010 
1011 	private void verifySafeObject(final AnyObjectId id, final int type,
1012 			final byte[] data) throws IOException {
1013 		if (objCheck != null) {
1014 			try {
1015 				objCheck.check(type, data);
1016 			} catch (CorruptObjectException e) {
1017 				throw new CorruptObjectException(MessageFormat.format(
1018 						JGitText.get().invalidObject,
1019 						Constants.typeString(type),
1020 						readCurs.abbreviate(id, 10).name(),
1021 						e.getMessage()), e);
1022 			}
1023 		}
1024 
1025 		try {
1026 			final ObjectLoader ldr = readCurs.open(id, type);
1027 			final byte[] existingData = ldr.getCachedBytes(data.length);
1028 			if (!Arrays.equals(data, existingData)) {
1029 				throw new IOException(MessageFormat.format(
1030 						JGitText.get().collisionOn, id.name()));
1031 			}
1032 		} catch (MissingObjectException notLocal) {
1033 			// This is OK, we don't have a copy of the object locally
1034 			// but the API throws when we try to read it as usually its
1035 			// an error to read something that doesn't exist.
1036 		}
1037 	}
1038 
1039 	private void doDeferredCheckBlobs() throws IOException {
1040 		final byte[] readBuffer = buffer();
1041 		final byte[] curBuffer = new byte[readBuffer.length];
1042 		ObjectTypeAndSize info = new ObjectTypeAndSize();
1043 
1044 		for (PackedObjectInfo obj : deferredCheckBlobs) {
1045 			info = openDatabase(obj, info);
1046 
1047 			if (info.type != Constants.OBJ_BLOB)
1048 				throw new IOException(MessageFormat.format(
1049 						JGitText.get().unknownObjectType,
1050 						Integer.valueOf(info.type)));
1051 
1052 			ObjectStream cur = readCurs.open(obj, info.type).openStream();
1053 			try {
1054 				long sz = info.size;
1055 				if (cur.getSize() != sz)
1056 					throw new IOException(MessageFormat.format(
1057 							JGitText.get().collisionOn, obj.name()));
1058 				InputStream pck = inflate(Source.DATABASE, sz);
1059 				while (0 < sz) {
1060 					int n = (int) Math.min(readBuffer.length, sz);
1061 					IO.readFully(cur, curBuffer, 0, n);
1062 					IO.readFully(pck, readBuffer, 0, n);
1063 					for (int i = 0; i < n; i++) {
1064 						if (curBuffer[i] != readBuffer[i])
1065 							throw new IOException(MessageFormat.format(JGitText
1066 									.get().collisionOn, obj.name()));
1067 					}
1068 					sz -= n;
1069 				}
1070 				pck.close();
1071 			} finally {
1072 				cur.close();
1073 			}
1074 		}
1075 	}
1076 
1077 	/** @return current position of the input stream being parsed. */
1078 	private long streamPosition() {
1079 		return bBase + bOffset;
1080 	}
1081 
1082 	private ObjectTypeAndSize openDatabase(PackedObjectInfo obj,
1083 			ObjectTypeAndSize info) throws IOException {
1084 		bOffset = 0;
1085 		bAvail = 0;
1086 		return seekDatabase(obj, info);
1087 	}
1088 
1089 	private ObjectTypeAndSize openDatabase(UnresolvedDelta delta,
1090 			ObjectTypeAndSize info) throws IOException {
1091 		bOffset = 0;
1092 		bAvail = 0;
1093 		return seekDatabase(delta, info);
1094 	}
1095 
1096 	// Consume exactly one byte from the buffer and return it.
1097 	private int readFrom(final Source src) throws IOException {
1098 		if (bAvail == 0)
1099 			fill(src, 1);
1100 		bAvail--;
1101 		return buf[bOffset++] & 0xff;
1102 	}
1103 
1104 	// Consume cnt bytes from the buffer.
1105 	private void use(final int cnt) {
1106 		bOffset += cnt;
1107 		bAvail -= cnt;
1108 	}
1109 
1110 	// Ensure at least need bytes are available in in {@link #buf}.
1111 	private int fill(final Source src, final int need) throws IOException {
1112 		while (bAvail < need) {
1113 			int next = bOffset + bAvail;
1114 			int free = buf.length - next;
1115 			if (free + bAvail < need) {
1116 				switch (src) {
1117 				case INPUT:
1118 					sync();
1119 					break;
1120 				case DATABASE:
1121 					if (bAvail > 0)
1122 						System.arraycopy(buf, bOffset, buf, 0, bAvail);
1123 					bOffset = 0;
1124 					break;
1125 				}
1126 				next = bAvail;
1127 				free = buf.length - next;
1128 			}
1129 			switch (src) {
1130 			case INPUT:
1131 				next = in.read(buf, next, free);
1132 				break;
1133 			case DATABASE:
1134 				next = readDatabase(buf, next, free);
1135 				break;
1136 			}
1137 			if (next <= 0)
1138 				throw new EOFException(
1139 						JGitText.get().packfileIsTruncatedNoParam);
1140 			bAvail += next;
1141 		}
1142 		return bOffset;
1143 	}
1144 
1145 	// Store consumed bytes in {@link #buf} up to {@link #bOffset}.
1146 	private void sync() throws IOException {
1147 		packDigest.update(buf, 0, bOffset);
1148 		onStoreStream(buf, 0, bOffset);
1149 		if (expectDataAfterPackFooter) {
1150 			if (bAvail > 0) {
1151 				in.reset();
1152 				IO.skipFully(in, bOffset);
1153 				bAvail = 0;
1154 			}
1155 			in.mark(buf.length);
1156 		} else if (bAvail > 0)
1157 			System.arraycopy(buf, bOffset, buf, 0, bAvail);
1158 		bBase += bOffset;
1159 		bOffset = 0;
1160 	}
1161 
1162 	/** @return a temporary byte array for use by the caller. */
1163 	protected byte[] buffer() {
1164 		return tempBuffer;
1165 	}
1166 
1167 	/**
1168 	 * Construct a PackedObjectInfo instance for this parser.
1169 	 *
1170 	 * @param id
1171 	 *            identity of the object to be tracked.
1172 	 * @param delta
1173 	 *            if the object was previously an unresolved delta, this is the
1174 	 *            delta object that was tracking it. Otherwise null.
1175 	 * @param deltaBase
1176 	 *            if the object was previously an unresolved delta, this is the
1177 	 *            ObjectId of the base of the delta. The base may be outside of
1178 	 *            the pack stream if the stream was a thin-pack.
1179 	 * @return info object containing this object's data.
1180 	 */
1181 	protected PackedObjectInfo newInfo(AnyObjectId id, UnresolvedDelta delta,
1182 			ObjectId deltaBase) {
1183 		PackedObjectInfo oe = new PackedObjectInfo(id);
1184 		if (delta != null)
1185 			oe.setCRC(delta.crc);
1186 		return oe;
1187 	}
1188 
1189 	/**
1190 	 * Store bytes received from the raw stream.
1191 	 * <p>
1192 	 * This method is invoked during {@link #parse(ProgressMonitor)} as data is
1193 	 * consumed from the incoming stream. Implementors may use this event to
1194 	 * archive the raw incoming stream to the destination repository in large
1195 	 * chunks, without paying attention to object boundaries.
1196 	 * <p>
1197 	 * The only component of the pack not supplied to this method is the last 20
1198 	 * bytes of the pack that comprise the trailing SHA-1 checksum. Those are
1199 	 * passed to {@link #onPackFooter(byte[])}.
1200 	 *
1201 	 * @param raw
1202 	 *            buffer to copy data out of.
1203 	 * @param pos
1204 	 *            first offset within the buffer that is valid.
1205 	 * @param len
1206 	 *            number of bytes in the buffer that are valid.
1207 	 * @throws IOException
1208 	 *             the stream cannot be archived.
1209 	 */
1210 	protected abstract void onStoreStream(byte[] raw, int pos, int len)
1211 			throws IOException;
1212 
1213 	/**
1214 	 * Store (and/or checksum) an object header.
1215 	 * <p>
1216 	 * Invoked after any of the {@code onBegin()} events. The entire header is
1217 	 * supplied in a single invocation, before any object data is supplied.
1218 	 *
1219 	 * @param src
1220 	 *            where the data came from
1221 	 * @param raw
1222 	 *            buffer to read data from.
1223 	 * @param pos
1224 	 *            first offset within buffer that is valid.
1225 	 * @param len
1226 	 *            number of bytes in buffer that are valid.
1227 	 * @throws IOException
1228 	 *             the stream cannot be archived.
1229 	 */
1230 	protected abstract void onObjectHeader(Source src, byte[] raw, int pos,
1231 			int len) throws IOException;
1232 
1233 	/**
1234 	 * Store (and/or checksum) a portion of an object's data.
1235 	 * <p>
1236 	 * This method may be invoked multiple times per object, depending on the
1237 	 * size of the object, the size of the parser's internal read buffer, and
1238 	 * the alignment of the object relative to the read buffer.
1239 	 * <p>
1240 	 * Invoked after {@link #onObjectHeader(Source, byte[], int, int)}.
1241 	 *
1242 	 * @param src
1243 	 *            where the data came from
1244 	 * @param raw
1245 	 *            buffer to read data from.
1246 	 * @param pos
1247 	 *            first offset within buffer that is valid.
1248 	 * @param len
1249 	 *            number of bytes in buffer that are valid.
1250 	 * @throws IOException
1251 	 *             the stream cannot be archived.
1252 	 */
1253 	protected abstract void onObjectData(Source src, byte[] raw, int pos,
1254 			int len) throws IOException;
1255 
1256 	/**
1257 	 * Invoked for commits, trees, tags, and small blobs.
1258 	 *
1259 	 * @param obj
1260 	 *            the object info, populated.
1261 	 * @param typeCode
1262 	 *            the type of the object.
1263 	 * @param data
1264 	 *            inflated data for the object.
1265 	 * @throws IOException
1266 	 *             the object cannot be archived.
1267 	 */
1268 	protected abstract void onInflatedObjectData(PackedObjectInfo obj,
1269 			int typeCode, byte[] data) throws IOException;
1270 
1271 	/**
1272 	 * Provide the implementation with the original stream's pack header.
1273 	 *
1274 	 * @param objCnt
1275 	 *            number of objects expected in the stream.
1276 	 * @throws IOException
1277 	 *             the implementation refuses to work with this many objects.
1278 	 */
1279 	protected abstract void onPackHeader(long objCnt) throws IOException;
1280 
1281 	/**
1282 	 * Provide the implementation with the original stream's pack footer.
1283 	 *
1284 	 * @param hash
1285 	 *            the trailing 20 bytes of the pack, this is a SHA-1 checksum of
1286 	 *            all of the pack data.
1287 	 * @throws IOException
1288 	 *             the stream cannot be archived.
1289 	 */
1290 	protected abstract void onPackFooter(byte[] hash) throws IOException;
1291 
1292 	/**
1293 	 * Provide the implementation with a base that was outside of the pack.
1294 	 * <p>
1295 	 * This event only occurs on a thin pack for base objects that were outside
1296 	 * of the pack and came from the local repository. Usually an implementation
1297 	 * uses this event to compress the base and append it onto the end of the
1298 	 * pack, so the pack stays self-contained.
1299 	 *
1300 	 * @param typeCode
1301 	 *            type of the base object.
1302 	 * @param data
1303 	 *            complete content of the base object.
1304 	 * @param info
1305 	 *            packed object information for this base. Implementors must
1306 	 *            populate the CRC and offset members if returning true.
1307 	 * @return true if the {@code info} should be included in the object list
1308 	 *         returned by {@link #getSortedObjectList(Comparator)}, false if it
1309 	 *         should not be included.
1310 	 * @throws IOException
1311 	 *             the base could not be included into the pack.
1312 	 */
1313 	protected abstract boolean onAppendBase(int typeCode, byte[] data,
1314 			PackedObjectInfo info) throws IOException;
1315 
1316 	/**
1317 	 * Event indicating a thin pack has been completely processed.
1318 	 * <p>
1319 	 * This event is invoked only if a thin pack has delta references to objects
1320 	 * external from the pack. The event is called after all of those deltas
1321 	 * have been resolved.
1322 	 *
1323 	 * @throws IOException
1324 	 *             the pack cannot be archived.
1325 	 */
1326 	protected abstract void onEndThinPack() throws IOException;
1327 
1328 	/**
1329 	 * Reposition the database to re-read a previously stored object.
1330 	 * <p>
1331 	 * If the database is computing CRC-32 checksums for object data, it should
1332 	 * reset its internal CRC instance during this method call.
1333 	 *
1334 	 * @param obj
1335 	 *            the object position to begin reading from. This is from
1336 	 *            {@link #newInfo(AnyObjectId, UnresolvedDelta, ObjectId)}.
1337 	 * @param info
1338 	 *            object to populate with type and size.
1339 	 * @return the {@code info} object.
1340 	 * @throws IOException
1341 	 *             the database cannot reposition to this location.
1342 	 */
1343 	protected abstract ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
1344 			ObjectTypeAndSize info) throws IOException;
1345 
1346 	/**
1347 	 * Reposition the database to re-read a previously stored object.
1348 	 * <p>
1349 	 * If the database is computing CRC-32 checksums for object data, it should
1350 	 * reset its internal CRC instance during this method call.
1351 	 *
1352 	 * @param delta
1353 	 *            the object position to begin reading from. This is an instance
1354 	 *            previously returned by {@link #onEndDelta()}.
1355 	 * @param info
1356 	 *            object to populate with type and size.
1357 	 * @return the {@code info} object.
1358 	 * @throws IOException
1359 	 *             the database cannot reposition to this location.
1360 	 */
1361 	protected abstract ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
1362 			ObjectTypeAndSize info) throws IOException;
1363 
1364 	/**
1365 	 * Read from the database's current position into the buffer.
1366 	 *
1367 	 * @param dst
1368 	 *            the buffer to copy read data into.
1369 	 * @param pos
1370 	 *            position within {@code dst} to start copying data into.
1371 	 * @param cnt
1372 	 *            ideal target number of bytes to read. Actual read length may
1373 	 *            be shorter.
1374 	 * @return number of bytes stored.
1375 	 * @throws IOException
1376 	 *             the database cannot be accessed.
1377 	 */
1378 	protected abstract int readDatabase(byte[] dst, int pos, int cnt)
1379 			throws IOException;
1380 
1381 	/**
1382 	 * Check the current CRC matches the expected value.
1383 	 * <p>
1384 	 * This method is invoked when an object is read back in from the database
1385 	 * and its data is used during delta resolution. The CRC is validated after
1386 	 * the object has been fully read, allowing the parser to verify there was
1387 	 * no silent data corruption.
1388 	 * <p>
1389 	 * Implementations are free to ignore this check by always returning true if
1390 	 * they are performing other data integrity validations at a lower level.
1391 	 *
1392 	 * @param oldCRC
1393 	 *            the prior CRC that was recorded during the first scan of the
1394 	 *            object from the pack stream.
1395 	 * @return true if the CRC matches; false if it does not.
1396 	 */
1397 	protected abstract boolean checkCRC(int oldCRC);
1398 
1399 	/**
1400 	 * Event notifying the start of an object stored whole (not as a delta).
1401 	 *
1402 	 * @param streamPosition
1403 	 *            position of this object in the incoming stream.
1404 	 * @param type
1405 	 *            type of the object; one of {@link Constants#OBJ_COMMIT},
1406 	 *            {@link Constants#OBJ_TREE}, {@link Constants#OBJ_BLOB}, or
1407 	 *            {@link Constants#OBJ_TAG}.
1408 	 * @param inflatedSize
1409 	 *            size of the object when fully inflated. The size stored within
1410 	 *            the pack may be larger or smaller, and is not yet known.
1411 	 * @throws IOException
1412 	 *             the object cannot be recorded.
1413 	 */
1414 	protected abstract void onBeginWholeObject(long streamPosition, int type,
1415 			long inflatedSize) throws IOException;
1416 
1417 	/**
1418 	 * Event notifying the the current object.
1419 	 *
1420 	 *@param info
1421 	 *            object information.
1422 	 * @throws IOException
1423 	 *             the object cannot be recorded.
1424 	 */
1425 	protected abstract void onEndWholeObject(PackedObjectInfo info)
1426 			throws IOException;
1427 
1428 	/**
1429 	 * Event notifying start of a delta referencing its base by offset.
1430 	 *
1431 	 * @param deltaStreamPosition
1432 	 *            position of this object in the incoming stream.
1433 	 * @param baseStreamPosition
1434 	 *            position of the base object in the incoming stream. The base
1435 	 *            must be before the delta, therefore {@code baseStreamPosition
1436 	 *            &lt; deltaStreamPosition}. This is <b>not</b> the position
1437 	 *            returned by a prior end object event.
1438 	 * @param inflatedSize
1439 	 *            size of the delta when fully inflated. The size stored within
1440 	 *            the pack may be larger or smaller, and is not yet known.
1441 	 * @throws IOException
1442 	 *             the object cannot be recorded.
1443 	 */
1444 	protected abstract void onBeginOfsDelta(long deltaStreamPosition,
1445 			long baseStreamPosition, long inflatedSize) throws IOException;
1446 
1447 	/**
1448 	 * Event notifying start of a delta referencing its base by ObjectId.
1449 	 *
1450 	 * @param deltaStreamPosition
1451 	 *            position of this object in the incoming stream.
1452 	 * @param baseId
1453 	 *            name of the base object. This object may be later in the
1454 	 *            stream, or might not appear at all in the stream (in the case
1455 	 *            of a thin-pack).
1456 	 * @param inflatedSize
1457 	 *            size of the delta when fully inflated. The size stored within
1458 	 *            the pack may be larger or smaller, and is not yet known.
1459 	 * @throws IOException
1460 	 *             the object cannot be recorded.
1461 	 */
1462 	protected abstract void onBeginRefDelta(long deltaStreamPosition,
1463 			AnyObjectId baseId, long inflatedSize) throws IOException;
1464 
1465 	/**
1466 	 * Event notifying the the current object.
1467 	 *
1468 	 *@return object information that must be populated with at least the
1469 	 *         offset.
1470 	 * @throws IOException
1471 	 *             the object cannot be recorded.
1472 	 */
1473 	protected UnresolvedDelta onEndDelta() throws IOException {
1474 		return new UnresolvedDelta();
1475 	}
1476 
1477 	/** Type and size information about an object in the database buffer. */
1478 	public static class ObjectTypeAndSize {
1479 		/** The type of the object. */
1480 		public int type;
1481 
1482 		/** The inflated size of the object. */
1483 		public long size;
1484 	}
1485 
1486 	private void inflateAndSkip(final Source src, final long inflatedSize)
1487 			throws IOException {
1488 		final InputStream inf = inflate(src, inflatedSize);
1489 		IO.skipFully(inf, inflatedSize);
1490 		inf.close();
1491 	}
1492 
1493 	private byte[] inflateAndReturn(final Source src, final long inflatedSize)
1494 			throws IOException {
1495 		final byte[] dst = new byte[(int) inflatedSize];
1496 		final InputStream inf = inflate(src, inflatedSize);
1497 		IO.readFully(inf, dst, 0, dst.length);
1498 		inf.close();
1499 		return dst;
1500 	}
1501 
1502 	private InputStream inflate(final Source src, final long inflatedSize)
1503 			throws IOException {
1504 		inflater.open(src, inflatedSize);
1505 		return inflater;
1506 	}
1507 
1508 	private static class DeltaChain extends ObjectIdOwnerMap.Entry {
1509 		UnresolvedDelta head;
1510 
1511 		DeltaChain(final AnyObjectId id) {
1512 			super(id);
1513 		}
1514 
1515 		UnresolvedDelta remove() {
1516 			final UnresolvedDelta r = head;
1517 			if (r != null)
1518 				head = null;
1519 			return r;
1520 		}
1521 
1522 		void add(final UnresolvedDelta d) {
1523 			d.next = head;
1524 			head = d;
1525 		}
1526 	}
1527 
1528 	/** Information about an unresolved delta in this pack stream. */
1529 	public static class UnresolvedDelta {
1530 		long position;
1531 
1532 		int crc;
1533 
1534 		UnresolvedDelta next;
1535 
1536 		/** @return offset within the input stream. */
1537 		public long getOffset() {
1538 			return position;
1539 		}
1540 
1541 		/** @return the CRC-32 checksum of the stored delta data. */
1542 		public int getCRC() {
1543 			return crc;
1544 		}
1545 
1546 		/**
1547 		 * @param crc32
1548 		 *            the CRC-32 checksum of the stored delta data.
1549 		 */
1550 		public void setCRC(int crc32) {
1551 			crc = crc32;
1552 		}
1553 	}
1554 
1555 	private static class DeltaVisit {
1556 		final UnresolvedDelta delta;
1557 
1558 		ObjectId id;
1559 
1560 		byte[] data;
1561 
1562 		DeltaVisit parent;
1563 
1564 		UnresolvedDelta nextChild;
1565 
1566 		DeltaVisit() {
1567 			this.delta = null; // At the root of the stack we have a base.
1568 		}
1569 
1570 		DeltaVisit(DeltaVisit parent) {
1571 			this.parent = parent;
1572 			this.delta = parent.nextChild;
1573 			parent.nextChild = delta.next;
1574 		}
1575 
1576 		DeltaVisit next() {
1577 			// If our parent has no more children, discard it.
1578 			if (parent != null && parent.nextChild == null) {
1579 				parent.data = null;
1580 				parent = parent.parent;
1581 			}
1582 
1583 			if (nextChild != null)
1584 				return new DeltaVisit(this);
1585 
1586 			// If we have no child ourselves, our parent must (if it exists),
1587 			// due to the discard rule above. With no parent, we are done.
1588 			if (parent != null)
1589 				return new DeltaVisit(parent);
1590 			return null;
1591 		}
1592 	}
1593 
1594 	private void addObjectAndTrack(PackedObjectInfo oe) {
1595 		entries[entryCount++] = oe;
1596 		if (needNewObjectIds())
1597 			newObjectIds.add(oe);
1598 	}
1599 
1600 	private class InflaterStream extends InputStream {
1601 		private final Inflater inf;
1602 
1603 		private final byte[] skipBuffer;
1604 
1605 		private Source src;
1606 
1607 		private long expectedSize;
1608 
1609 		private long actualSize;
1610 
1611 		private int p;
1612 
1613 		InflaterStream() {
1614 			inf = InflaterCache.get();
1615 			skipBuffer = new byte[512];
1616 		}
1617 
1618 		void release() {
1619 			inf.reset();
1620 			InflaterCache.release(inf);
1621 		}
1622 
1623 		void open(Source source, long inflatedSize) throws IOException {
1624 			src = source;
1625 			expectedSize = inflatedSize;
1626 			actualSize = 0;
1627 
1628 			p = fill(src, 1);
1629 			inf.setInput(buf, p, bAvail);
1630 		}
1631 
1632 		@Override
1633 		public long skip(long toSkip) throws IOException {
1634 			long n = 0;
1635 			while (n < toSkip) {
1636 				final int cnt = (int) Math.min(skipBuffer.length, toSkip - n);
1637 				final int r = read(skipBuffer, 0, cnt);
1638 				if (r <= 0)
1639 					break;
1640 				n += r;
1641 			}
1642 			return n;
1643 		}
1644 
1645 		@Override
1646 		public int read() throws IOException {
1647 			int n = read(skipBuffer, 0, 1);
1648 			return n == 1 ? skipBuffer[0] & 0xff : -1;
1649 		}
1650 
1651 		@Override
1652 		public int read(byte[] dst, int pos, int cnt) throws IOException {
1653 			try {
1654 				int n = 0;
1655 				while (n < cnt) {
1656 					int r = inf.inflate(dst, pos + n, cnt - n);
1657 					n += r;
1658 					if (inf.finished())
1659 						break;
1660 					if (inf.needsInput()) {
1661 						onObjectData(src, buf, p, bAvail);
1662 						use(bAvail);
1663 
1664 						p = fill(src, 1);
1665 						inf.setInput(buf, p, bAvail);
1666 					} else if (r == 0) {
1667 						throw new CorruptObjectException(MessageFormat.format(
1668 								JGitText.get().packfileCorruptionDetected,
1669 								JGitText.get().unknownZlibError));
1670 					}
1671 				}
1672 				actualSize += n;
1673 				return 0 < n ? n : -1;
1674 			} catch (DataFormatException dfe) {
1675 				throw new CorruptObjectException(MessageFormat.format(JGitText
1676 						.get().packfileCorruptionDetected, dfe.getMessage()));
1677 			}
1678 		}
1679 
1680 		@Override
1681 		public void close() throws IOException {
1682 			// We need to read here to enter the loop above and pump the
1683 			// trailing checksum into the Inflater. It should return -1 as the
1684 			// caller was supposed to consume all content.
1685 			//
1686 			if (read(skipBuffer) != -1 || actualSize != expectedSize) {
1687 				throw new CorruptObjectException(MessageFormat.format(JGitText
1688 						.get().packfileCorruptionDetected,
1689 						JGitText.get().wrongDecompressedLength));
1690 			}
1691 
1692 			int used = bAvail - inf.getRemaining();
1693 			if (0 < used) {
1694 				onObjectData(src, buf, p, used);
1695 				use(used);
1696 			}
1697 
1698 			inf.reset();
1699 		}
1700 	}
1701 }