public void testSkip() throws IOException { init(32, 15); copy(2, 2); insert("ab"); insert("cd"); copy(4, 4); copy(0, 2); insert("efg"); assertValidState(); for (int p = 0; p < data.length; p++) { byte[] act = new byte[data.length]; System.arraycopy(data, 0, act, 0, p); DeltaStream in = open(); IO.skipFully(in, p); assertEquals(data.length - p, in.read(act, p, data.length - p)); assertEquals(-1, in.read()); assertTrue("skipping " + p, Arrays.equals(data, act)); } // Skip all the way to the end should still recognize EOF. DeltaStream in = open(); IO.skipFully(in, data.length); assertEquals(-1, in.read()); assertEquals(0, in.skip(1)); // Skip should not open the base as we move past it, but it // will open when we need to start copying data from it. final boolean[] opened = new boolean[1]; in = new DeltaStream(new ByteArrayInputStream(delta)) { @Override protected long getBaseSize() throws IOException { return base.length; } @Override protected InputStream openBase() throws IOException { opened[0] = true; return new ByteArrayInputStream(base); } }; IO.skipFully(in, 7); assertFalse("not yet open", opened[0]); assertEquals(data[7], in.read()); assertTrue("now open", opened[0]); }
private void readFrom(final InputStream inStream) throws IOException, CorruptObjectException { final BufferedInputStream in = new BufferedInputStream(inStream); final MessageDigest md = Constants.newMessageDigest(); // Read the index header and verify we understand it. // final byte[] hdr = new byte[20]; IO.readFully(in, hdr, 0, 12); md.update(hdr, 0, 12); if (!is_DIRC(hdr)) throw new CorruptObjectException(JGitText.get().notADIRCFile); final int ver = NB.decodeInt32(hdr, 4); boolean extended = false; if (ver == 3) extended = true; else if (ver != 2) throw new CorruptObjectException( MessageFormat.format(JGitText.get().unknownDIRCVersion, Integer.valueOf(ver))); entryCnt = NB.decodeInt32(hdr, 8); if (entryCnt < 0) throw new CorruptObjectException(JGitText.get().DIRCHasTooManyEntries); snapshot = FileSnapshot.save(liveFile); int smudge_s = (int) (snapshot.lastModified() / 1000); int smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000; // Load the individual file entries. // final int infoLength = DirCacheEntry.getMaximumInfoLength(extended); final byte[] infos = new byte[infoLength * entryCnt]; sortedEntries = new DirCacheEntry[entryCnt]; final MutableInteger infoAt = new MutableInteger(); for (int i = 0; i < entryCnt; i++) sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md, smudge_s, smudge_ns); // After the file entries are index extensions, and then a footer. // for (; ; ) { in.mark(21); IO.readFully(in, hdr, 0, 20); if (in.read() < 0) { // No extensions present; the file ended where we expected. // break; } in.reset(); md.update(hdr, 0, 8); IO.skipFully(in, 8); long sz = NB.decodeUInt32(hdr, 4); switch (NB.decodeInt32(hdr, 0)) { case EXT_TREE: { if (Integer.MAX_VALUE < sz) { throw new CorruptObjectException( MessageFormat.format( JGitText.get().DIRCExtensionIsTooLargeAt, formatExtensionName(hdr), Long.valueOf(sz))); } final byte[] raw = new byte[(int) sz]; IO.readFully(in, raw, 0, raw.length); md.update(raw, 0, raw.length); tree = new DirCacheTree(raw, new MutableInteger(), null); break; } default: if (hdr[0] >= 'A' && hdr[0] <= 'Z') { // The extension is optional and is here only as // a performance optimization. Since we do not // understand it, we can safely skip past it, after // we include its data in our checksum. // skipOptionalExtension(in, md, hdr, sz); } else { // The extension is not an optimization and is // _required_ to understand this index format. // Since we did not trap it above we must abort. // throw new CorruptObjectException( MessageFormat.format( JGitText.get().DIRCExtensionNotSupportedByThisVersion, formatExtensionName(hdr))); } } } readIndexChecksum = md.digest(); if (!Arrays.equals(readIndexChecksum, hdr)) { throw new CorruptObjectException(JGitText.get().DIRCChecksumMismatch); } }