return block.length;
}
- int remaining(long pos) {
- int ptr = (int) (pos - start);
- return block.length - ptr;
- }
-
boolean contains(DfsPackKey want, long pos) {
return pack == want && start <= pos && pos < end;
}
return n;
}
- void setInput(Inflater inf, long pos) {
+ int setInput(long pos, Inflater inf) {
int ptr = (int) (pos - start);
- inf.setInput(block, ptr, block.length - ptr);
+ int cnt = block.length - ptr;
+ inf.setInput(block, ptr, cnt);
+ return cnt;
}
void crc32(CRC32 out, long pos, int cnt) {
}
Inflater inf = ctx.inflater();
- DfsBlock b = setInput(inf, pos);
+ pos += setInput(pos, inf);
for (int dstoff = 0;;) {
int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
- if (n > 0)
- dstoff += n;
- else if (inf.needsInput() && b != null) {
- pos += b.remaining(pos);
- b = setInput(inf, pos);
- } else if (inf.needsInput())
- throw new EOFException(DfsText.get().unexpectedEofInPack);
- else if (inf.finished())
+ dstoff += n;
+ if (inf.finished())
return dstbuf;
- else
+ if (inf.needsInput())
+ pos += setInput(pos, inf);
+ else if (n == 0)
throw new DataFormatException();
}
}
- private DfsBlock setInput(Inflater inf, long pos) throws IOException {
- if (pos < currPos) {
- DfsBlock b = getOrLoadBlock(pos);
- b.setInput(inf, pos);
- return b;
+ private int setInput(long pos, Inflater inf) throws IOException {
+ if (pos < currPos)
+ return getOrLoadBlock(pos).setInput(pos, inf);
+ if (pos < currPos + currPtr) {
+ int s = (int) (pos - currPos);
+ int n = currPtr - s;
+ inf.setInput(currBuf, s, n);
+ return n;
}
- inf.setInput(currBuf, (int) (pos - currPos), currPtr);
- return null;
+ throw new EOFException(DfsText.get().unexpectedEofInPack);
}
private DfsBlock getOrLoadBlock(long pos) throws IOException {
* position within the file to read from.
* @param dstbuf
* destination buffer the inflater should output decompressed
- * data to.
+ * data to. Must be large enough to store the entire stream,
+ * unless headerOnly is true.
* @param headerOnly
* if true the caller wants only {@code dstbuf.length} bytes.
- * @return updated <code>dstoff</code> based on the number of bytes
- * successfully inflated into <code>dstbuf</code>.
+ * @return number of bytes inflated into <code>dstbuf</code>.
* @throws IOException
* this cursor does not match the provider or id and the proper
* window could not be acquired through the provider's cache.
boolean headerOnly) throws IOException, DataFormatException {
prepareInflater();
pin(pack, position);
- block.setInput(inf, position);
- int dstoff = 0;
- for (;;) {
+ position += block.setInput(position, inf);
+ for (int dstoff = 0;;) {
int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
- if (n == 0) {
- if (headerOnly && dstoff == dstbuf.length)
- return dstoff;
- if (inf.needsInput()) {
- position += block.remaining(position);
- pin(pack, position);
- block.setInput(inf, position);
- continue;
- }
- if (inf.finished())
- return dstoff;
- throw new DataFormatException();
- }
dstoff += n;
+ if (inf.finished() || (headerOnly && dstoff == dstbuf.length))
+ return dstoff;
+ if (inf.needsInput()) {
+ pin(pack, position);
+ position += block.setInput(position, inf);
+ } else if (n == 0)
+ throw new DataFormatException();
}
}
return null;
}
- if (curs.inflate(this, position, dstbuf, 0) != sz)
+ if (curs.inflate(this, position, dstbuf, false) != sz)
throw new EOFException(MessageFormat.format(
JGitText.get().shortCompressedStreamAt,
Long.valueOf(position)));
// the longest delta instruction header.
//
final byte[] hdr = new byte[18];
- wc.inflate(this, pos, hdr, 0);
+ wc.inflate(this, pos, hdr, true /* headerOnly */);
return hdr;
}
* position within the file to read from.
* @param dstbuf
* destination buffer the inflater should output decompressed
- * data to.
- * @param dstoff
- * current offset within <code>dstbuf</code> to inflate into.
- * @return updated <code>dstoff</code> based on the number of bytes
- * successfully inflated into <code>dstbuf</code>.
+ * data to. Must be large enough to store the entire stream,
+ * unless headerOnly is true.
+ * @param headerOnly
+ * if true the caller wants only {@code dstbuf.length} bytes.
+ * @return number of bytes inflated into <code>dstbuf</code>.
* @throws IOException
* this cursor does not match the provider or id and the proper
* window could not be acquired through the provider's cache.
* stream corruption is likely.
*/
int inflate(final PackFile pack, long position, final byte[] dstbuf,
- int dstoff) throws IOException, DataFormatException {
+ boolean headerOnly) throws IOException, DataFormatException {
prepareInflater();
pin(pack, position);
position += window.setInput(position, inf);
- do {
+ for (int dstoff = 0;;) {
int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
- if (n == 0) {
- if (inf.needsInput()) {
- pin(pack, position);
- position += window.setInput(position, inf);
- } else if (inf.finished())
- return dstoff;
- else
- throw new DataFormatException();
- }
dstoff += n;
- } while (dstoff < dstbuf.length);
- return dstoff;
+ if (inf.finished() || (headerOnly && dstoff == dstbuf.length))
+ return dstoff;
+ if (inf.needsInput()) {
+ pin(pack, position);
+ position += window.setInput(position, inf);
+ } else if (n == 0)
+ throw new DataFormatException();
+ }
}
ByteArrayWindow quickCopy(PackFile p, long pos, long cnt)
int n = 0;
while (n < cnt) {
int r = inf.inflate(dst, pos + n, cnt - n);
- if (r == 0) {
- if (inf.finished())
- break;
- if (inf.needsInput()) {
- onObjectData(src, buf, p, bAvail);
- use(bAvail);
-
- p = fill(src, 1);
- inf.setInput(buf, p, bAvail);
- } else {
- throw new CorruptObjectException(
- MessageFormat
- .format(
- JGitText.get().packfileCorruptionDetected,
- JGitText.get().unknownZlibError));
- }
- } else {
- n += r;
+ n += r;
+ if (inf.finished())
+ break;
+ if (inf.needsInput()) {
+ onObjectData(src, buf, p, bAvail);
+ use(bAvail);
+
+ p = fill(src, 1);
+ inf.setInput(buf, p, bAvail);
+ } else if (r == 0) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().packfileCorruptionDetected,
+ JGitText.get().unknownZlibError));
}
}
actualSize += n;