comparison src/org/tmatesoft/hg/internal/InflaterDataAccess.java @ 158:b413b16d10a5

Integer offsets and file length explictly, rather than casts throughout code. Inflater may benefit from total length hint, but shall calculate it by its own if needed
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 09 Mar 2011 13:16:37 +0100
parents d5268ca7715b
children 31f67be94e71
comparison
equal deleted inserted replaced
157:d5268ca7715b 158:b413b16d10a5
20 import java.io.IOException; 20 import java.io.IOException;
21 import java.util.zip.DataFormatException; 21 import java.util.zip.DataFormatException;
22 import java.util.zip.Inflater; 22 import java.util.zip.Inflater;
23 import java.util.zip.ZipException; 23 import java.util.zip.ZipException;
24 24
25 import org.tmatesoft.hg.core.HgBadStateException;
26
25 27
26 /** 28 /**
27 * DataAccess counterpart for InflaterInputStream. 29 * DataAccess counterpart for InflaterInputStream.
28 * XXX is it really needed to be subclass of FilterDataAccess? 30 * XXX is it really needed to be subclass of FilterDataAccess?
29 * 31 *
34 36
35 private final Inflater inflater; 37 private final Inflater inflater;
36 private final byte[] buffer; 38 private final byte[] buffer;
37 private final byte[] singleByte = new byte[1]; 39 private final byte[] singleByte = new byte[1];
38 private int decompressedPos = 0; 40 private int decompressedPos = 0;
39 private int decompressedLength = -1; 41 private int decompressedLength;
40 42
41 public InflaterDataAccess(DataAccess dataAccess, long offset, int length) { 43 public InflaterDataAccess(DataAccess dataAccess, int offset, int compressedLength) {
42 this(dataAccess, offset, length, new Inflater(), 512); 44 this(dataAccess, offset, compressedLength, -1, new Inflater(), 512);
43 } 45 }
44 46
45 public InflaterDataAccess(DataAccess dataAccess, long offset, int length, Inflater inflater, int bufSize) { 47 public InflaterDataAccess(DataAccess dataAccess, int offset, int compressedLength, int actualLength) {
46 super(dataAccess, offset, length); 48 this(dataAccess, offset, compressedLength, actualLength, new Inflater(), 512);
49 }
50
51 public InflaterDataAccess(DataAccess dataAccess, int offset, int compressedLength, int actualLength, Inflater inflater, int bufSize) {
52 super(dataAccess, offset, compressedLength);
47 this.inflater = inflater; 53 this.inflater = inflater;
54 this.decompressedLength = actualLength;
48 buffer = new byte[bufSize]; 55 buffer = new byte[bufSize];
49 } 56 }
50 57
51 @Override 58 @Override
52 public InflaterDataAccess reset() throws IOException { 59 public InflaterDataAccess reset() throws IOException {
56 return this; 63 return this;
57 } 64 }
58 65
59 @Override 66 @Override
60 protected int available() { 67 protected int available() {
61 throw new IllegalStateException("Can't tell how much uncompressed data left"); 68 return length() - decompressedPos;
62 } 69 }
63 70
64 @Override 71 @Override
65 public boolean isEmpty() { 72 public boolean isEmpty() {
66 return super.available() <= 0 && inflater.finished(); // and/or inflater.getRemaining() <= 0 ? 73 // can't use super.available() <= 0 because even when 0 < super.count < 6(?)
74 // decompressedPos might be already == length()
75 return available() <= 0;
67 } 76 }
68 77
69 @Override 78 @Override
70 public long length() { 79 public int length() {
71 if (decompressedLength != -1) { 80 if (decompressedLength != -1) {
72 return decompressedLength; 81 return decompressedLength;
73 } 82 }
83 decompressedLength = 0; // guard to avoid endless loop in case length() would get invoked from below.
74 int c = 0; 84 int c = 0;
75 try { 85 try {
76 int oldPos = decompressedPos; 86 int oldPos = decompressedPos;
77 while (!isEmpty()) { 87 byte[] dummy = new byte[buffer.length];
78 readByte(); 88 int toRead;
79 c++; 89 while ((toRead = super.available()) > 0) {
90 if (toRead > buffer.length) {
91 toRead = buffer.length;
92 }
93 super.readBytes(buffer, 0, toRead);
94 inflater.setInput(buffer, 0, toRead);
95 try {
96 while (!inflater.needsInput()) {
97 c += inflater.inflate(dummy, 0, dummy.length);
98 }
99 } catch (DataFormatException ex) {
100 throw new HgBadStateException(ex);
101 }
80 } 102 }
81 decompressedLength = c + oldPos; 103 decompressedLength = c + oldPos;
82 reset(); 104 reset();
83 seek(oldPos); 105 seek(oldPos);
84 return decompressedLength; 106 return decompressedLength;
85 } catch (IOException ex) { 107 } catch (IOException ex) {
86 ex.printStackTrace(); // FIXME log error
87 decompressedLength = -1; // better luck next time? 108 decompressedLength = -1; // better luck next time?
88 return 0; 109 throw new HgBadStateException(ex); // XXX perhaps, checked exception
89 } 110 }
90 } 111 }
91 112
92 @Override 113 @Override
93 public void seek(long localOffset) throws IOException { 114 public void seek(int localOffset) throws IOException {
94 if (localOffset < 0 /* || localOffset >= length() */) { 115 if (localOffset < 0 /* || localOffset >= length() */) {
95 throw new IllegalArgumentException(); 116 throw new IllegalArgumentException();
96 } 117 }
97 if (localOffset >= decompressedPos) { 118 if (localOffset >= decompressedPos) {
98 skip((int) (localOffset - decompressedPos)); 119 skip((int) (localOffset - decompressedPos));