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