ASF Bugzilla – Attachment 34068 Details for
Bug 59893
Forbid calls to InputStream.available
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
replace available() calls and add forbidden-apis-check
forbid-available.diff (text/plain), 94.86 KB, created by
Andreas Beeker
on 2016-07-23 18:01:57 UTC
(
hide
)
Description:
replace available() calls and add forbidden-apis-check
Filename:
MIME Type:
Creator:
Andreas Beeker
Created:
2016-07-23 18:01:57 UTC
Size:
94.86 KB
patch
obsolete
>Index: src/examples/src/org/apache/poi/poifs/poibrowser/DocumentDescriptor.java >=================================================================== >--- src/examples/src/org/apache/poi/poifs/poibrowser/DocumentDescriptor.java (revision 1753737) >+++ src/examples/src/org/apache/poi/poifs/poibrowser/DocumentDescriptor.java (working copy) >@@ -17,8 +17,11 @@ > > package org.apache.poi.poifs.poibrowser; > >-import java.io.*; >-import org.apache.poi.poifs.filesystem.*; >+import java.io.IOException; >+ >+import org.apache.poi.poifs.filesystem.DocumentInputStream; >+import org.apache.poi.poifs.filesystem.POIFSDocumentPath; >+import org.apache.poi.util.IOUtils; > > /** > * <p>Describes the most important (whatever that is) features of a >@@ -49,26 +52,20 @@ > public DocumentDescriptor(final String name, > final POIFSDocumentPath path, > final DocumentInputStream stream, >- final int nrOfBytes) >- { >+ final int nrOfBytes) { > this.name = name; > this.path = path; > this.stream = stream; >- try >- { >- size = stream.available(); >- if (stream.markSupported()) >- { >+ try { >+ if (stream.markSupported()) { > stream.mark(nrOfBytes); >- final byte[] b = new byte[nrOfBytes]; >- final int read = stream.read(b, 0, Math.min(size, b.length)); >- bytes = new byte[read]; >- System.arraycopy(b, 0, bytes, 0, read); >+ bytes = IOUtils.toByteArray(stream, nrOfBytes); > stream.reset(); >+ } else { >+ bytes = new byte[0]; > } >- } >- catch (IOException ex) >- { >+ size = bytes.length + stream.available(); >+ } catch (IOException ex) { > System.out.println(ex); > } > } >Index: src/examples/src/org/apache/poi/poifs/poibrowser/TreeReaderListener.java >=================================================================== >--- src/examples/src/org/apache/poi/poifs/poibrowser/TreeReaderListener.java (revision 1753737) >+++ src/examples/src/org/apache/poi/poifs/poibrowser/TreeReaderListener.java (working copy) >@@ -121,13 +121,15 @@ > * reading. This method retrieves properties of the document and > * adds them to a tree model.</p> > */ >+ @Override > public void processPOIFSReaderEvent(final POIFSReaderEvent event) > { > DocumentDescriptor d; > final DocumentInputStream is = event.getStream(); >- if (!is.markSupported()) >+ if (!is.markSupported()) { > throw new UnsupportedOperationException(is.getClass().getName() + > " does not support mark()."); >+ } > > /* Try do handle this document as a property set. We receive > * an exception if is no property set and handle it as a >@@ -149,7 +151,7 @@ > ("Unexpected exception while processing " + > event.getName() + " in " + event.getPath().toString()); > t.printStackTrace(System.err); >- throw new RuntimeException(t.getMessage()); >+ throw new RuntimeException(t); > } > > is.close(); >@@ -180,9 +182,10 @@ > final MutableTreeNode root) > { > MutableTreeNode n = pathToNode.get(path); >- if (n != null) >+ if (n != null) { > /* Node found in map, just return it. */ > return n; >+ } > if (path.length() == 0) > { > /* This is the root path of the POI filesystem. Its tree >Index: src/java/org/apache/poi/hpsf/PropertySet.java >=================================================================== >--- src/java/org/apache/poi/hpsf/PropertySet.java (revision 1753737) >+++ src/java/org/apache/poi/hpsf/PropertySet.java (working copy) >@@ -26,6 +26,7 @@ > import org.apache.poi.hpsf.wellknown.SectionIDMap; > import org.apache.poi.util.IOUtils; > import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.LittleEndianConsts; > > /** > * <p>Represents a property set in the Horrible Property Set Format >@@ -235,15 +236,11 @@ > throws NoPropertySetStreamException, MarkUnsupportedException, > IOException, UnsupportedEncodingException > { >- if (isPropertySetStream(stream)) >- { >- final int avail = stream.available(); >- final byte[] buffer = new byte[avail]; >- IOUtils.readFully(stream, buffer); >- init(buffer, 0, buffer.length); >- } >- else >+ if (!isPropertySetStream(stream)) { > throw new NoPropertySetStreamException(); >+ } >+ final byte[] buffer = IOUtils.toByteArray(stream); >+ init(buffer, 0, buffer.length); > } > > >@@ -266,10 +263,11 @@ > public PropertySet(final byte[] stream, final int offset, final int length) > throws NoPropertySetStreamException, UnsupportedEncodingException > { >- if (isPropertySetStream(stream, offset, length)) >+ if (isPropertySetStream(stream, offset, length)) { > init(stream, offset, length); >- else >+ } else { > throw new NoPropertySetStreamException(); >+ } > } > > >@@ -322,25 +320,19 @@ > * reset to this position if the stream does not contain a > * property set. > */ >- if (!stream.markSupported()) >+ if (!stream.markSupported()) { > throw new MarkUnsupportedException(stream.getClass().getName()); >+ } > stream.mark(BUFFER_SIZE); > > /* > * Read a couple of bytes from the stream. > */ >- final byte[] buffer = new byte[BUFFER_SIZE]; >- final int bytes = >- stream.read(buffer, 0, >- Math.min(buffer.length, stream.available())); >- final boolean isPropertySetStream = >- isPropertySetStream(buffer, 0, bytes); >+ final byte[] buffer = IOUtils.toByteArray(stream, -BUFFER_SIZE); > stream.reset(); >- return isPropertySetStream; >+ return (buffer.length > 0 && isPropertySetStream(buffer, 0, buffer.length)); > } > >- >- > /** > * <p>Checks whether a byte array is in the Horrible Property Set > * Format.</p> >@@ -364,25 +356,28 @@ > */ > int o = offset; > final int byteOrder = LittleEndian.getUShort(src, o); >- o += LittleEndian.SHORT_SIZE; >- byte[] temp = new byte[LittleEndian.SHORT_SIZE]; >+ o += LittleEndianConsts.SHORT_SIZE; >+ byte[] temp = new byte[LittleEndianConsts.SHORT_SIZE]; > LittleEndian.putShort(temp, 0, (short) byteOrder); >- if (!Util.equal(temp, BYTE_ORDER_ASSERTION)) >+ if (!Util.equal(temp, BYTE_ORDER_ASSERTION)) { > return false; >+ } > final int format = LittleEndian.getUShort(src, o); >- o += LittleEndian.SHORT_SIZE; >- temp = new byte[LittleEndian.SHORT_SIZE]; >+ o += LittleEndianConsts.SHORT_SIZE; >+ temp = new byte[LittleEndianConsts.SHORT_SIZE]; > LittleEndian.putShort(temp, 0, (short) format); >- if (!Util.equal(temp, FORMAT_ASSERTION)) >+ if (!Util.equal(temp, FORMAT_ASSERTION)) { > return false; >+ } > // final long osVersion = LittleEndian.getUInt(src, offset); >- o += LittleEndian.INT_SIZE; >+ o += LittleEndianConsts.INT_SIZE; > // final ClassID classID = new ClassID(src, offset); > o += ClassID.LENGTH; > final long sectionCount = LittleEndian.getUInt(src, o); >- o += LittleEndian.INT_SIZE; >- if (sectionCount < 0) >+ o += LittleEndianConsts.INT_SIZE; >+ if (sectionCount < 0) { > return false; >+ } > return true; > } > >@@ -411,18 +406,19 @@ > */ > int o = offset; > byteOrder = LittleEndian.getUShort(src, o); >- o += LittleEndian.SHORT_SIZE; >+ o += LittleEndianConsts.SHORT_SIZE; > format = LittleEndian.getUShort(src, o); >- o += LittleEndian.SHORT_SIZE; >+ o += LittleEndianConsts.SHORT_SIZE; > osVersion = (int) LittleEndian.getUInt(src, o); >- o += LittleEndian.INT_SIZE; >+ o += LittleEndianConsts.INT_SIZE; > classID = new ClassID(src, o); > o += ClassID.LENGTH; > final int sectionCount = LittleEndian.getInt(src, o); >- o += LittleEndian.INT_SIZE; >- if (sectionCount < 0) >+ o += LittleEndianConsts.INT_SIZE; >+ if (sectionCount < 0) { > throw new HPSFRuntimeException("Section count " + sectionCount + > " is negative."); >+ } > > /* > * Read the sections, which are following the header. They >@@ -446,7 +442,7 @@ > for (int i = 0; i < sectionCount; i++) > { > final Section s = new Section(src, o); >- o += ClassID.LENGTH + LittleEndian.INT_SIZE; >+ o += ClassID.LENGTH + LittleEndianConsts.INT_SIZE; > sections.add(s); > } > } >@@ -462,8 +458,9 @@ > */ > public boolean isSummaryInformation() > { >- if (sections.size() <= 0) >+ if (sections.size() <= 0) { > return false; >+ } > return Util.equal(sections.get(0).getFormatID().getBytes(), > SectionIDMap.SUMMARY_INFORMATION_ID); > } >@@ -479,8 +476,9 @@ > */ > public boolean isDocumentSummaryInformation() > { >- if (sections.size() <= 0) >+ if (sections.size() <= 0) { > return false; >+ } > return Util.equal(sections.get(0).getFormatID().getBytes(), > SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]); > } >@@ -595,8 +593,9 @@ > */ > public Section getFirstSection() > { >- if (getSectionCount() < 1) >+ if (getSectionCount() < 1) { > throw new MissingSectionException("Property set does not contain any sections."); >+ } > return sections.get(0); > } > >@@ -611,9 +610,10 @@ > public Section getSingleSection() > { > final int sectionCount = getSectionCount(); >- if (sectionCount != 1) >+ if (sectionCount != 1) { > throw new NoSingleSectionException > ("Property set contains " + sectionCount + " sections."); >+ } > return sections.get(0); > } > >@@ -631,8 +631,9 @@ > @Override > public boolean equals(final Object o) > { >- if (o == null || !(o instanceof PropertySet)) >+ if (o == null || !(o instanceof PropertySet)) { > return false; >+ } > final PropertySet ps = (PropertySet) o; > int byteOrder1 = ps.getByteOrder(); > int byteOrder2 = getByteOrder(); >@@ -648,8 +649,9 @@ > !classID1.equals(classID2) || > format1 != format2 || > osVersion1 != osVersion2 || >- sectionCount1 != sectionCount2) >+ sectionCount1 != sectionCount2) { > return false; >+ } > > /* Compare the sections: */ > return Util.equals(getSections(), ps.getSections()); >@@ -660,6 +662,7 @@ > /** > * @see Object#hashCode() > */ >+ @Override > public int hashCode() > { > throw new UnsupportedOperationException("FIXME: Not yet implemented."); >@@ -670,6 +673,7 @@ > /** > * @see Object#toString() > */ >+ @Override > public String toString() > { > final StringBuilder b = new StringBuilder(); >@@ -687,8 +691,9 @@ > b.append(", sectionCount: "); > b.append(sectionCount); > b.append(", sections: [\n"); >- for (Section section: getSections()) >+ for (Section section: getSections()) { > b.append(section); >+ } > b.append(']'); > b.append(']'); > return b.toString(); >Index: src/java/org/apache/poi/hssf/dev/BiffViewer.java >=================================================================== >--- src/java/org/apache/poi/hssf/dev/BiffViewer.java (revision 1753737) >+++ src/java/org/apache/poi/hssf/dev/BiffViewer.java (working copy) >@@ -194,10 +194,12 @@ > import org.apache.poi.hssf.usermodel.HSSFWorkbook; > import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; > import org.apache.poi.util.HexDump; >+import org.apache.poi.util.IOUtils; > import org.apache.poi.util.LittleEndian; > import org.apache.poi.util.POILogFactory; > import org.apache.poi.util.POILogger; > import org.apache.poi.util.StringUtil; >+import org.apache.poi.util.SuppressForbidden; > > /** > * Utility for reading in BIFF8 records and displaying data from them. >@@ -567,10 +569,7 @@ > > try { > if (cmdArgs.shouldOutputRawHexOnly()) { >- int size = is.available(); >- byte[] data = new byte[size]; >- >- is.read(data); >+ byte[] data = IOUtils.toByteArray(is); > HexDump.dump(data, 0, System.out, 0); > } else { > boolean dumpInterpretedRecords = cmdArgs.shouldDumpRecordInterpretations(); >@@ -620,7 +619,9 @@ > public void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, > byte[] data) { > String header = formatRecordDetails(globalOffset, sid, dataSize, recordCounter); >- if(!_noHeader) _headers.add(header); >+ if(!_noHeader) { >+ _headers.add(header); >+ } > Writer w = _hexDumpWriter; > if (w != null) { > try { >@@ -710,12 +711,13 @@ > } > System.arraycopy(_data, _currentPos, b, off, result); > _currentPos += result; >- _overallStreamPos += result; >+ _overallStreamPos += result; > formatBufferIfAtEndOfRec(); > return result; > } > > @Override >+ @SuppressForbidden("just delegating the call") > public int available() throws IOException { > return _currentSize - _currentPos + _is.available(); > } >Index: src/java/org/apache/poi/hssf/record/ObjRecord.java >=================================================================== >--- src/java/org/apache/poi/hssf/record/ObjRecord.java (revision 1753737) >+++ src/java/org/apache/poi/hssf/record/ObjRecord.java (working copy) >@@ -18,10 +18,13 @@ > package org.apache.poi.hssf.record; > > import java.io.ByteArrayInputStream; >+import java.io.IOException; >+import java.io.InputStream; > import java.util.ArrayList; > import java.util.List; > > import org.apache.poi.util.HexDump; >+import org.apache.poi.util.IOUtils; > import org.apache.poi.util.LittleEndian; > import org.apache.poi.util.LittleEndianByteArrayOutputStream; > import org.apache.poi.util.LittleEndianInputStream; >@@ -58,12 +61,10 @@ > public ObjRecord(RecordInputStream in) { > // TODO - problems with OBJ sub-records stream > // MS spec says first sub-record is always CommonObjectDataSubRecord, >- // and last is >- // always EndSubRecord. OOO spec does not mention ObjRecord(0x005D). >+ // and last is always EndSubRecord. OOO spec does not mention ObjRecord(0x005D). > // Existing POI test data seems to violate that rule. Some test data >- // seems to contain >- // garbage, and a crash is only averted by stopping at what looks like >- // the 'EndSubRecord' >+ // seems to contain garbage, and a crash is only averted by stopping at >+ // what looks like the 'EndSubRecord' > > // Check if this can be continued, if so then the > // following wont work properly >@@ -88,61 +89,77 @@ > subrecords = new ArrayList<SubRecord>(); > ByteArrayInputStream bais = new ByteArrayInputStream(subRecordData); > LittleEndianInputStream subRecStream = new LittleEndianInputStream(bais); >- CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)SubRecord.createSubRecord(subRecStream, 0); >- subrecords.add(cmo); >- while (true) { >- SubRecord subRecord = SubRecord.createSubRecord(subRecStream, cmo.getObjectType()); >- subrecords.add(subRecord); >- if (subRecord.isTerminating()) { >- break; >- } >- } >- int nRemainingBytes = bais.available(); >- if (nRemainingBytes > 0) { >- // At present (Oct-2008), most unit test samples have (subRecordData.length % 2 == 0) >- _isPaddedToQuadByteMultiple = subRecordData.length % MAX_PAD_ALIGNMENT == 0; >- if (nRemainingBytes >= (_isPaddedToQuadByteMultiple ? MAX_PAD_ALIGNMENT : NORMAL_PAD_ALIGNMENT)) { >- if (!canPaddingBeDiscarded(subRecordData, nRemainingBytes)) { >- String msg = "Leftover " + nRemainingBytes >- + " bytes in subrecord data " + HexDump.toHex(subRecordData); >- throw new RecordFormatException(msg); >- } >- _isPaddedToQuadByteMultiple = false; >- } >- >- } else { >- _isPaddedToQuadByteMultiple = false; >+ try { >+ CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)SubRecord.createSubRecord(subRecStream, 0); >+ subrecords.add(cmo); >+ SubRecord subRecord; >+ do { >+ subRecord = SubRecord.createSubRecord(subRecStream, cmo.getObjectType()); >+ subrecords.add(subRecord); >+ } while (!subRecord.isTerminating()); >+ >+ _isPaddedToQuadByteMultiple = isPaddedToQuadByteMultiple(bais, subRecordData.length); >+ _uninterpretedData = null; >+ } finally { >+ try { >+ subRecStream.close(); >+ } catch (IOException e) { >+ throw new RuntimeException(e); >+ } > } >- _uninterpretedData = null; > } > >- /** >- * Some XLS files have ObjRecords with nearly 8Kb of excessive padding. These were probably >- * written by a version of POI (around 3.1) which incorrectly interpreted the second short of >- * the ftLbs subrecord (0x1FEE) as a length, and read that many bytes as padding (other bugs >- * helped allow this to occur). >- * >- * Excel reads files with this excessive padding OK, truncating the over-sized ObjRecord back >- * to the its proper size. POI does the same. >- */ >- private static boolean canPaddingBeDiscarded(byte[] data, int nRemainingBytes) { >- // make sure none of the padding looks important >- for(int i=data.length-nRemainingBytes; i<data.length; i++) { >- if (data[i] != 0x00) { >- return false; >- } >- } >- return true; >+ /** >+ * Some XLS files have ObjRecords with nearly 8Kb of excessive padding. These were probably >+ * written by a version of POI (around 3.1) which incorrectly interpreted the second short of >+ * the ftLbs subrecord (0x1FEE) as a length, and read that many bytes as padding (other bugs >+ * helped allow this to occur). >+ * >+ * Excel reads files with this excessive padding OK, truncating the over-sized ObjRecord back >+ * to the its proper size. POI does the same. >+ */ >+ private static boolean isPaddedToQuadByteMultiple(InputStream remainingBytes, int subRecordDataLen) { >+ byte nRemainingBytes[]; >+ try { >+ nRemainingBytes = IOUtils.toByteArray(remainingBytes); >+ } catch (IOException e) { >+ throw new RuntimeException(e); >+ } >+ if (nRemainingBytes.length == 0) { >+ return false; >+ } >+ >+ boolean dataInPadding = false; >+ for (byte b : nRemainingBytes) { >+ // make sure none of the padding looks important >+ if (b != 0) { >+ dataInPadding = true; >+ break; >+ } >+ } >+ >+ // At present (Oct-2008), most unit test samples have (subRecordData.length % 2 == 0) >+ boolean isPaddedToQuad = (subRecordDataLen % MAX_PAD_ALIGNMENT) == 0; >+ int padAlignment = isPaddedToQuad ? MAX_PAD_ALIGNMENT : NORMAL_PAD_ALIGNMENT; >+ >+ if (nRemainingBytes.length >= padAlignment) { >+ if (dataInPadding) { >+ String msg = "Leftover bytes in subrecord data " + HexDump.toHex(nRemainingBytes); >+ throw new RecordFormatException(msg); >+ } >+ isPaddedToQuad = false; >+ } >+ >+ return isPaddedToQuad; > } > > @Override > public String toString() { >- StringBuffer sb = new StringBuffer(); >+ StringBuilder sb = new StringBuilder(); > > sb.append("[OBJ]\n"); > if(subrecords != null) { // there are special cases where this can be, see comments in constructor above >- for (int i = 0; i < subrecords.size(); i++) { >- SubRecord record = subrecords.get(i); >+ for (SubRecord record : subrecords) { > sb.append("SUBRECORD: ").append(record.toString()); > } > } >@@ -183,8 +200,7 @@ > > if (_uninterpretedData == null) { > >- for (int i = 0; i < subrecords.size(); i++) { >- SubRecord record = subrecords.get(i); >+ for (SubRecord record : subrecords) { > record.serialize(out); > } > int expectedEndIx = offset+dataSize; >@@ -223,9 +239,8 @@ > public ObjRecord clone() { > ObjRecord rec = new ObjRecord(); > >- for (int i = 0; i < subrecords.size(); i++) { >- SubRecord record = subrecords.get(i); >- rec.addSubRecord((SubRecord) record.clone()); >+ for (SubRecord record : subrecords) { >+ rec.addSubRecord(record.clone()); > } > return rec; > } >Index: src/java/org/apache/poi/hssf/record/SubRecord.java >=================================================================== >--- src/java/org/apache/poi/hssf/record/SubRecord.java (revision 1753737) >+++ src/java/org/apache/poi/hssf/record/SubRecord.java (working copy) >@@ -23,6 +23,7 @@ > import org.apache.poi.util.LittleEndianOutputStream; > > import java.io.ByteArrayOutputStream; >+import java.io.IOException; > > /** > * Subrecords are part of the OBJ class. >@@ -76,15 +77,26 @@ > public byte[] serialize() { > int size = getDataSize() + 4; > ByteArrayOutputStream baos = new ByteArrayOutputStream(size); >- serialize(new LittleEndianOutputStream(baos)); >- if (baos.size() != size) { >- throw new RuntimeException("write size mismatch"); >+ LittleEndianOutputStream leos = new LittleEndianOutputStream(baos); >+ try { >+ serialize(leos); >+ if (baos.size() != size) { >+ throw new RuntimeException("write size mismatch"); >+ } >+ return baos.toByteArray(); >+ } finally { >+ try { >+ leos.close(); >+ } catch (IOException e) { >+ throw new RuntimeException(e); >+ } > } >- return baos.toByteArray(); > } > > public abstract void serialize(LittleEndianOutput out); >- public abstract Object clone(); >+ >+ @Override >+ public abstract SubRecord clone(); > > /** > * Wether this record terminates the sub-record stream. >@@ -109,18 +121,26 @@ > in.readFully(buf); > _data = buf; > } >- protected int getDataSize() { >+ >+ @Override >+ protected int getDataSize() { > return _data.length; > } >- public void serialize(LittleEndianOutput out) { >+ >+ @Override >+ public void serialize(LittleEndianOutput out) { > out.writeShort(_sid); > out.writeShort(_data.length); > out.write(_data); > } >- public Object clone() { >+ >+ @Override >+ public UnknownSubRecord clone() { > return this; > } >- public String toString() { >+ >+ @Override >+ public String toString() { > StringBuffer sb = new StringBuffer(64); > sb.append(getClass().getName()).append(" ["); > sb.append("sid=").append(HexDump.shortToHex(_sid)); >Index: src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java >=================================================================== >--- src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherInputStream.java (working copy) >@@ -35,9 +35,10 @@ > > private int _lastIndex = 0; > private long _pos = 0; >- private long _size; >- private byte[] _chunk; >- private Cipher _cipher; >+ private final long _size; >+ private final byte[] _chunk; >+ private boolean _chunkValid; >+ private final Cipher _cipher; > > public ChunkedCipherInputStream(LittleEndianInput stream, long size, int chunkSize) > throws GeneralSecurityException { >@@ -46,38 +47,40 @@ > this.chunkSize = chunkSize; > chunkMask = chunkSize-1; > chunkBits = Integer.bitCount(chunkMask); >- >+ _chunk = new byte[chunkSize]; >+ _chunkValid = false; > _cipher = initCipherForBlock(null, 0); > } > > protected abstract Cipher initCipherForBlock(Cipher existing, int block) > throws GeneralSecurityException; > >+ @Override > public int read() throws IOException { >- byte[] b = new byte[1]; >- if (read(b) == 1) >- return b[0]; >- return -1; >+ byte[] b = { 0 }; >+ return (read(b) == -1) ? -1 : b[0]; > } > > // do not implement! -> recursion > // public int read(byte[] b) throws IOException; > >+ @Override > public int read(byte[] b, int off, int len) throws IOException { > int total = 0; > >- if (available() <= 0) return -1; >+ if (remainingBytes() <= 0) { >+ return -1; >+ } > > while (len > 0) { >- if (_chunk == null) { >- try { >- _chunk = nextChunk(); >- } catch (GeneralSecurityException e) { >- throw new EncryptedDocumentException(e.getMessage(), e); >- } >+ int tmp = -1; >+ if (!_chunkValid) { >+ tmp = nextChunk(); >+ _chunkValid = true; > } > int count = (int)(chunkSize - (_pos & chunkMask)); >- int avail = available(); >+ int avail = remainingBytes(); >+ assert(tmp == chunkSize || tmp == -1 || avail <= tmp); > if (avail == 0) { > return total; > } >@@ -86,8 +89,9 @@ > off += count; > len -= count; > _pos += count; >- if ((_pos & chunkMask) == 0) >- _chunk = null; >+ if ((_pos & chunkMask) == 0) { >+ _chunkValid = false; >+ } > total += count; > } > >@@ -97,16 +101,22 @@ > @Override > public long skip(long n) throws IOException { > long start = _pos; >- long skip = Math.min(available(), n); >+ long skip = Math.min(remainingBytes(), n); > >- if ((((_pos + skip) ^ start) & ~chunkMask) != 0) >- _chunk = null; >+ if ((((_pos + skip) ^ start) & ~chunkMask) != 0) { >+ _chunkValid = false; >+ } > _pos += skip; > return skip; > } > > @Override > public int available() { >+ return remainingBytes(); >+ } >+ >+ // helper method (... for forbidden-apis-check :) ...) >+ private int remainingBytes() { > return (int)(_size - _pos); > } > >@@ -125,17 +135,35 @@ > throw new UnsupportedOperationException(); > } > >- private byte[] nextChunk() throws GeneralSecurityException, IOException { >- int index = (int)(_pos >> chunkBits); >- initCipherForBlock(_cipher, index); >+ /** >+ * Read the next chunk from the super InputStream. >+ * This also handles non-continued reads, because of {@link #skip(long)} calls. >+ * >+ * @return the actual chunk size, which might be less than {@link #chunkSize} >+ * @throws IOException if the underlying stream can't be read >+ */ >+ private int nextChunk() throws IOException { >+ final int index = (int)(_pos >> chunkBits); > > if (_lastIndex != index) { > super.skip((index - _lastIndex) << chunkBits); > } >- >- byte[] block = new byte[Math.min(super.available(), chunkSize)]; >- super.read(block, 0, block.length); > _lastIndex = index + 1; >- return _cipher.doFinal(block); >+ >+ >+ int totalBytes = 0; >+ for (int readBytes; totalBytes < chunkSize; totalBytes += readBytes) { >+ readBytes = super.read(_chunk, totalBytes, chunkSize-totalBytes); >+ if (readBytes == -1) { >+ break; >+ } >+ } >+ >+ try { >+ initCipherForBlock(_cipher, index); >+ return _cipher.doFinal(_chunk, 0, totalBytes, _chunk); >+ } catch (GeneralSecurityException e) { >+ throw new EncryptedDocumentException(e.getMessage(), e); >+ } > } > } >Index: src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java >=================================================================== >--- src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (working copy) >@@ -53,6 +53,7 @@ > > private long _pos = 0; > private Cipher _cipher; >+ private boolean isClosed = false; > > public ChunkedCipherOutputStream(DirectoryNode dir, int chunkSize) throws IOException, GeneralSecurityException { > super(null); >@@ -134,6 +135,13 @@ > } > > public void close() throws IOException { >+ if (isClosed) { >+ logger.log(POILogger.DEBUG, "ChunkedCipherOutputStream was already closed - ignoring"); >+ return; >+ } >+ >+ isClosed = true; >+ > try { > writeChunk(); > >Index: src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java >=================================================================== >--- src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java (working copy) >@@ -15,13 +15,14 @@ > See the License for the specific language governing permissions and > limitations under the License. > ==================================================================== */ >- > >-package org.apache.poi.poifs.eventfilesystem; > >-import java.io.*; >+package org.apache.poi.poifs.eventfilesystem; > >-import java.util.*; >+import java.io.FileInputStream; >+import java.io.IOException; >+import java.io.InputStream; >+import java.util.Iterator; > > import org.apache.poi.poifs.filesystem.DocumentInputStream; > import org.apache.poi.poifs.filesystem.OPOIFSDocument; >@@ -34,6 +35,7 @@ > import org.apache.poi.poifs.storage.HeaderBlock; > import org.apache.poi.poifs.storage.RawDataBlockList; > import org.apache.poi.poifs.storage.SmallBlockTableReader; >+import org.apache.poi.util.IOUtils; > > /** > * An event-driven reader for POIFS file systems. Users of this class >@@ -42,8 +44,6 @@ > * documents. Once all the listeners have been registered, the read() > * method is called, which results in the listeners being notified as > * their documents are read. >- * >- * @author Marc Johnson (mjohnson at apache dot org) > */ > > public class POIFSReader >@@ -97,8 +97,8 @@ > processProperties(SmallBlockTableReader > .getSmallDocumentBlocks( > header_block.getBigBlockSize(), >- data_blocks, properties.getRoot(), >- header_block.getSBATStart()), >+ data_blocks, properties.getRoot(), >+ header_block.getSBATStart()), > data_blocks, properties.getRoot() > .getChildren(), new POIFSDocumentPath()); > } >@@ -196,14 +196,13 @@ > } > > // register for all >- for (int j = 0; j < args.length; j++) >- { >+ for (String arg : args) { > POIFSReader reader = new POIFSReader(); > POIFSReaderListener listener = new SampleListener(); > > reader.registerListener(listener); >- System.out.println("reading " + args[ j ]); >- FileInputStream istream = new FileInputStream(args[ j ]); >+ System.out.println("reading " + arg); >+ FileInputStream istream = new FileInputStream(arg); > > reader.read(istream); > istream.close(); >@@ -258,11 +257,12 @@ > while (listeners.hasNext()) > { > POIFSReaderListener listener = listeners.next(); >- >- listener.processPOIFSReaderEvent( >- new POIFSReaderEvent( >- new DocumentInputStream(document), path, >- name)); >+ DocumentInputStream dis = new DocumentInputStream(document); >+ try { >+ listener.processPOIFSReaderEvent(new POIFSReaderEvent(dis, path, name)); >+ } finally { >+ dis.close(); >+ } > } > } > else >@@ -300,6 +300,7 @@ > * @param event > */ > >+ @Override > public void processPOIFSReaderEvent(final POIFSReaderEvent event) > { > @SuppressWarnings("resource") >@@ -309,9 +310,7 @@ > > try > { >- byte[] data = new byte[ istream.available() ]; >- >- istream.read(data); >+ byte[] data = IOUtils.toByteArray(istream); > int pathLength = path.length(); > > for (int k = 0; k < pathLength; k++) >Index: src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java >=================================================================== >--- src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java (working copy) >@@ -21,6 +21,7 @@ > import java.io.InputStream; > > import org.apache.poi.util.LittleEndianInput; >+import org.apache.poi.util.SuppressForbidden; > > /** > * This class provides methods to read a DocumentEntry managed by a >@@ -86,6 +87,7 @@ > } > > @Override >+ @SuppressForbidden("just delegating") > public int available() { > return delegate.available(); > } >Index: src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java >=================================================================== >--- src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java (working copy) >@@ -40,13 +40,13 @@ > private int _marked_offset_count; > > /** the Document's size */ >- private int _document_size; >+ private final int _document_size; > > /** have we been closed? */ > private boolean _closed; > > /** the actual Document */ >- private NPOIFSDocument _document; >+ private final NPOIFSDocument _document; > > private Iterator<ByteBuffer> _data; > private ByteBuffer _buffer; >@@ -97,12 +97,21 @@ > > @Override > public int available() { >+ return remainingBytes(); >+ } >+ >+ /** >+ * Helper methods for forbidden api calls >+ * >+ * @return the bytes remaining until the end of the stream >+ */ >+ private int remainingBytes() { > if (_closed) { > throw new IllegalStateException("cannot perform requested operation on a closed stream"); > } > return _document_size - _current_offset; > } >- >+ > @Override > public void close() { > _closed = true; >@@ -146,7 +155,7 @@ > if (atEOD()) { > return EOF; > } >- int limit = Math.min(available(), len); >+ int limit = Math.min(remainingBytes(), len); > readFully(b, off, limit); > return limit; > } >@@ -302,8 +311,9 @@ > checkAvaliable(1); > byte[] data = new byte[1]; > readFully(data, 0, 1); >- if(data[0] >= 0) >- return data[0]; >+ if(data[0] >= 0) { >+ return data[0]; >+ } > return data[0] + 256; > } > } >Index: src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java >=================================================================== >--- src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java (working copy) >@@ -33,13 +33,13 @@ > private int _marked_offset; > > /** the Document's size */ >- private int _document_size; >+ private final int _document_size; > > /** have we been closed? */ > private boolean _closed; > > /** the actual Document */ >- private OPOIFSDocument _document; >+ private final OPOIFSDocument _document; > > /** the data block containing the current stream pointer */ > private DataInputBlock _currentBlock; >@@ -134,7 +134,7 @@ > if (atEOD()) { > return EOF; > } >- int limit = Math.min(available(), len); >+ int limit = Math.min(_document_size - _current_offset, len); > readFully(b, off, limit); > return limit; > } >Index: src/java/org/apache/poi/util/BlockingInputStream.java >=================================================================== >--- src/java/org/apache/poi/util/BlockingInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/util/BlockingInputStream.java (working copy) >@@ -28,12 +28,13 @@ > * data from slow (ie, non FileInputStream) sources, for example when > * reading an OLE2 Document over a network. > * >- * Possible extentions: add a timeout. Curently a call to read(byte[]) on this >+ * Possible extensions: add a timeout. Currently a call to read(byte[]) on this > * class is blocking, so use at your own peril if your underlying stream blocks. > * >- * @author Jens Gerhard >- * @author aviks - documentation cleanups. >+ * @deprecated in POI 3.15 - unused class > */ >+@Deprecated >+@Removal(version="3.17") > public class BlockingInputStream > extends InputStream > { >@@ -44,6 +45,7 @@ > this.is = is; > } > >+ @SuppressForbidden("just delegating the call") > public int available() > throws IOException > { >Index: src/java/org/apache/poi/util/BoundedInputStream.java >=================================================================== >--- src/java/org/apache/poi/util/BoundedInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/util/BoundedInputStream.java (working copy) >@@ -146,6 +146,7 @@ > * {@inheritDoc} > */ > @Override >+ @SuppressForbidden("just delegating") > public int available() throws IOException { > if (max>=0 && pos>=max) { > return 0; >Index: src/java/org/apache/poi/util/IOUtils.java >=================================================================== >--- src/java/org/apache/poi/util/IOUtils.java (revision 1753737) >+++ src/java/org/apache/poi/util/IOUtils.java (working copy) >@@ -74,21 +74,30 @@ > > /** > * Reads up to {@code length} bytes from the input stream, and returns the bytes read. >+ * >+ * @param stream the stream to read from >+ * @param length the amount of bytes to be read, if {@code length} is {@value Integer.MAX_VALUE} >+ * or negative, the byte length is not checked >+ * >+ * @return the read bytes >+ * >+ * @throws IOException if {@code length} can't be read. the check is omitted, if {@code length} is negative > */ >- public static byte[] toByteArray(InputStream stream, int length) throws IOException { >- ByteArrayOutputStream baos = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? 4096 : length); >+ public static byte[] toByteArray(InputStream stream, final int length) throws IOException { >+ final int len = Math.abs(length); >+ ByteArrayOutputStream baos = new ByteArrayOutputStream(len == Integer.MAX_VALUE ? 4096 : len); > > byte[] buffer = new byte[4096]; > int totalBytes = 0, readBytes; > do { >- readBytes = stream.read(buffer, 0, Math.min(buffer.length, length-totalBytes)); >+ readBytes = stream.read(buffer, 0, Math.min(buffer.length, len-totalBytes)); > totalBytes += Math.max(readBytes,0); > if (readBytes > 0) { > baos.write(buffer, 0, readBytes); > } >- } while (totalBytes < length && readBytes > -1); >+ } while (totalBytes < len && readBytes > -1); > >- if (length != Integer.MAX_VALUE && totalBytes < length) { >+ if (length >= 0 && len != Integer.MAX_VALUE && totalBytes < len) { > throw new IOException("unexpected EOF"); > } > >Index: src/java/org/apache/poi/util/LittleEndianInputStream.java >=================================================================== >--- src/java/org/apache/poi/util/LittleEndianInputStream.java (revision 1753737) >+++ src/java/org/apache/poi/util/LittleEndianInputStream.java (working copy) >@@ -26,14 +26,14 @@ > * > * This class does not buffer any input, so the stream read position maintained > * by this class is consistent with that of the inner stream. >- * >- * @author Josh Micich > */ > public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput { > public LittleEndianInputStream(InputStream is) { > super(is); > } > >+ @Override >+ @SuppressForbidden("just delegating") > public int available() { > try { > return super.available(); >@@ -42,11 +42,13 @@ > } > } > >- public byte readByte() { >+ @Override >+ public byte readByte() { > return (byte)readUByte(); > } > >- public int readUByte() { >+ @Override >+ public int readUByte() { > byte buf[] = new byte[1]; > try { > checkEOF(read(buf), 1); >@@ -56,11 +58,13 @@ > return LittleEndian.getUByte(buf); > } > >- public double readDouble() { >+ @Override >+ public double readDouble() { > return Double.longBitsToDouble(readLong()); > } > >- public int readInt() { >+ @Override >+ public int readInt() { > byte buf[] = new byte[LittleEndianConsts.INT_SIZE]; > try { > checkEOF(read(buf), buf.length); >@@ -82,7 +86,8 @@ > return retNum & 0x00FFFFFFFFL; > } > >- public long readLong() { >+ @Override >+ public long readLong() { > byte buf[] = new byte[LittleEndianConsts.LONG_SIZE]; > try { > checkEOF(read(buf), LittleEndianConsts.LONG_SIZE); >@@ -92,11 +97,13 @@ > return LittleEndian.getLong(buf); > } > >- public short readShort() { >+ @Override >+ public short readShort() { > return (short)readUShort(); > } > >- public int readUShort() { >+ @Override >+ public int readUShort() { > byte buf[] = new byte[LittleEndianConsts.SHORT_SIZE]; > try { > checkEOF(read(buf), LittleEndianConsts.SHORT_SIZE); >@@ -112,11 +119,13 @@ > } > } > >- public void readFully(byte[] buf) { >+ @Override >+ public void readFully(byte[] buf) { > readFully(buf, 0, buf.length); > } > >- public void readFully(byte[] buf, int off, int len) { >+ @Override >+ public void readFully(byte[] buf, int off, int len) { > try { > checkEOF(read(buf, off, len), len); > } catch (IOException e) { >Index: src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java >=================================================================== >--- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java (revision 1753737) >+++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java (working copy) >@@ -41,6 +41,7 @@ > import org.apache.poi.poifs.storage.HeaderBlockConstants; > import org.apache.poi.util.IOUtils; > import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.Removal; > > public final class ZipHelper { > /** >@@ -53,7 +54,11 @@ > * Buffer to read data from file. Use big buffer to improve performaces. the > * InputStream class is reading only 8192 bytes per read call (default value > * set by sun) >+ * >+ * @deprecated in POI 3.15-beta3, not used anymore > */ >+ @Deprecated >+ @Removal(version="3.17") > public static final int READ_WRITE_FILE_BUFFER_SIZE = 8192; > > /** >@@ -73,8 +78,9 @@ > PackageRelationship corePropsRel = pkg.getRelationshipsByType( > PackageRelationshipTypes.CORE_PROPERTIES).getRelationship(0); > >- if (corePropsRel == null) >+ if (corePropsRel == null) { > return null; >+ } > > return new ZipEntry(corePropsRel.getTargetURI().getPath()); > } >@@ -90,8 +96,9 @@ > while (entries.hasMoreElements()) { > ZipEntry entry = entries.nextElement(); > if (entry.getName().equals( >- ContentTypeManager.CONTENT_TYPES_PART_NAME)) >+ ContentTypeManager.CONTENT_TYPES_PART_NAME)) { > return entry; >+ } > } > return null; > } >@@ -105,8 +112,9 @@ > * @return An OPC compliant name. > */ > public static String getOPCNameFromZipItemName(String zipItemName) { >- if (zipItemName == null) >+ if (zipItemName == null) { > throw new IllegalArgumentException("zipItemName"); >+ } > if (zipItemName.startsWith(FORWARD_SLASH)) { > return zipItemName; > } >@@ -122,12 +130,14 @@ > * @return A zip item name without any leading slashes. > */ > public static String getZipItemNameFromOPCName(String opcItemName) { >- if (opcItemName == null) >+ if (opcItemName == null) { > throw new IllegalArgumentException("opcItemName"); >+ } > > String retVal = opcItemName; >- while (retVal.startsWith(FORWARD_SLASH)) >+ while (retVal.startsWith(FORWARD_SLASH)) { > retVal = retVal.substring(1); >+ } > return retVal; > } > >@@ -140,12 +150,14 @@ > * @return A zip URI without any leading slashes. > */ > public static URI getZipURIFromOPCName(String opcItemName) { >- if (opcItemName == null) >+ if (opcItemName == null) { > throw new IllegalArgumentException("opcItemName"); >+ } > > String retVal = opcItemName; >- while (retVal.startsWith(FORWARD_SLASH)) >+ while (retVal.startsWith(FORWARD_SLASH)) { > retVal = retVal.substring(1); >+ } > try { > return new URI(retVal); > } catch (URISyntaxException e) { >Index: src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java >=================================================================== >--- src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java (revision 1753737) >+++ src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java (working copy) >@@ -36,6 +36,7 @@ > import org.apache.poi.openxml4j.opc.internal.PartMarshaller; > import org.apache.poi.openxml4j.opc.internal.ZipHelper; > import org.apache.poi.util.DocumentHelper; >+import org.apache.poi.util.IOUtils; > import org.apache.poi.util.POILogFactory; > import org.apache.poi.util.POILogger; > import org.apache.poi.xssf.usermodel.XSSFRelation; >@@ -44,8 +45,6 @@ > > /** > * Zip part marshaller. This marshaller is use to save any part in a zip stream. >- * >- * @author Julien Chable > */ > public final class ZipPartMarshaller implements PartMarshaller { > private static POILogger logger = POILogFactory.getLogger(ZipPartMarshaller.class); >@@ -56,7 +55,8 @@ > * @throws OpenXML4JException > * Throws if an internal exception is thrown. > */ >- public boolean marshall(PackagePart part, OutputStream os) >+ @Override >+ public boolean marshall(PackagePart part, OutputStream os) > throws OpenXML4JException { > if (!(os instanceof ZipOutputStream)) { > logger.log(POILogger.ERROR,"Unexpected class " + os.getClass().getName()); >@@ -81,19 +81,12 @@ > > // Saving data in the ZIP file > InputStream ins = part.getInputStream(); >- byte[] buff = new byte[ZipHelper.READ_WRITE_FILE_BUFFER_SIZE]; >- while (ins.available() > 0) { >- int resultRead = ins.read(buff); >- if (resultRead == -1) { >- // End of file reached >- break; >- } >- zos.write(buff, 0, resultRead); >- } >+ IOUtils.copy(ins, zos); >+ ins.close(); >+ > zos.closeEntry(); > } catch (IOException ioe) { >- logger.log(POILogger.ERROR,"Cannot write: " + part.getPartName() + ": in ZIP", >- ioe); >+ logger.log(POILogger.ERROR,"Cannot write: " + part.getPartName() + ": in ZIP", ioe); > return false; > } > >Index: src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java >=================================================================== >--- src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java (revision 1753737) >+++ src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java (working copy) >@@ -160,16 +160,19 @@ > * @throws IOException if an I/O error has occurred > * @throws IllegalStateException if the zip file has been closed > */ >+ @Override > @SuppressWarnings("resource") > public InputStream getInputStream(ZipEntry entry) throws IOException { > InputStream zipIS = super.getInputStream(entry); > return addThreshold(zipIS); > } > >+ @SuppressWarnings("resource") > public static ThresholdInputStream addThreshold(final InputStream zipIS) throws IOException { > ThresholdInputStream newInner; > if (zipIS instanceof InflaterInputStream) { > newInner = AccessController.doPrivileged(new PrivilegedAction<ThresholdInputStream>() { >+ @Override > @SuppressForbidden("TODO: Fix this to not use reflection (it will break in Java 9)! " + > "Better would be to wrap *before* instead of tyring to insert wrapper afterwards.") > public ThresholdInputStream run() { >@@ -177,9 +180,9 @@ > Field f = FilterInputStream.class.getDeclaredField("in"); > f.setAccessible(true); > InputStream oldInner = (InputStream)f.get(zipIS); >- ThresholdInputStream newInner = new ThresholdInputStream(oldInner, null); >- f.set(zipIS, newInner); >- return newInner; >+ ThresholdInputStream newInner2 = new ThresholdInputStream(oldInner, null); >+ f.set(zipIS, newInner2); >+ return newInner2; > } catch (Exception ex) { > logger.log(POILogger.WARN, "SecurityManager doesn't allow manipulation via reflection for zipbomb detection - continue with original input stream", ex); > } >@@ -203,24 +206,32 @@ > this.cis = cis; > } > >+ @Override > public int read() throws IOException { > int b = in.read(); >- if (b > -1) advance(1); >+ if (b > -1) { >+ advance(1); >+ } > return b; > } > >+ @Override > public int read(byte b[], int off, int len) throws IOException { > int cnt = in.read(b, off, len); >- if (cnt > -1) advance(cnt); >+ if (cnt > -1) { >+ advance(cnt); >+ } > return cnt; > > } > >+ @Override > public long skip(long n) throws IOException { > counter = 0; > return in.skip(n); > } > >+ @Override > public synchronized void reset() throws IOException { > counter = 0; > in.reset(); >@@ -277,31 +288,41 @@ > ((ZipInputStream)in).closeEntry(); > } > >+ @Override > public void unread(int b) throws IOException { > if (!(in instanceof PushbackInputStream)) { > throw new UnsupportedOperationException("underlying stream is not a PushbackInputStream"); > } >- if (--counter < 0) counter = 0; >+ if (--counter < 0) { >+ counter = 0; >+ } > ((PushbackInputStream)in).unread(b); > } > >+ @Override > public void unread(byte[] b, int off, int len) throws IOException { > if (!(in instanceof PushbackInputStream)) { > throw new UnsupportedOperationException("underlying stream is not a PushbackInputStream"); > } > counter -= len; >- if (--counter < 0) counter = 0; >+ if (--counter < 0) { >+ counter = 0; >+ } > ((PushbackInputStream)in).unread(b, off, len); > } > >+ @Override >+ @SuppressForbidden("just delegating") > public int available() throws IOException { > return in.available(); > } > >+ @Override > public boolean markSupported() { > return in.markSupported(); > } > >+ @Override > public synchronized void mark(int readlimit) { > in.mark(readlimit); > } >Index: src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java (revision 1753737) >+++ src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java (working copy) >@@ -30,6 +30,7 @@ > > import org.apache.poi.POIXMLProperties.CoreProperties; > import org.apache.poi.openxml4j.util.Nullable; >+import org.apache.poi.util.IOUtils; > import org.apache.poi.util.LocaleUtil; > import org.apache.poi.xssf.XSSFTestDataSamples; > import org.apache.poi.xssf.usermodel.XSSFWorkbook; >@@ -249,13 +250,13 @@ > assertNotNull(noThumbProps.getThumbnailPart()); > assertEquals("Testing.png", noThumbProps.getThumbnailFilename()); > assertNotNull(noThumbProps.getThumbnailImage()); >- assertEquals(1, noThumbProps.getThumbnailImage().available()); >+ assertEquals(1, IOUtils.toByteArray(noThumbProps.getThumbnailImage()).length); > > noThumbProps.setThumbnail("Testing2.png", new ByteArrayInputStream(new byte[2])); > assertNotNull(noThumbProps.getThumbnailPart()); > assertEquals("Testing.png", noThumbProps.getThumbnailFilename()); > assertNotNull(noThumbProps.getThumbnailImage()); >- assertEquals(2, noThumbProps.getThumbnailImage().available()); >+ assertEquals(2, IOUtils.toByteArray(noThumbProps.getThumbnailImage()).length); > } > > private static String zeroPad(long i) { >Index: src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java (revision 1753737) >+++ src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java (working copy) >@@ -37,10 +37,6 @@ > import org.apache.poi.xssf.XSSFTestDataSamples; > import org.junit.Test; > >-/** >- * @author Maxim Valyanskiy >- * @author Gary King >- */ > public class TestDecryptor { > @Test > public void passwordVerification() throws IOException, GeneralSecurityException { >@@ -51,6 +47,8 @@ > Decryptor d = Decryptor.getInstance(info); > > assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD)); >+ >+ fs.close(); > } > > @Test >@@ -64,6 +62,8 @@ > d.verifyPassword(Decryptor.DEFAULT_PASSWORD); > > zipOk(fs.getRoot(), d); >+ >+ fs.close(); > } > > @Test >@@ -79,6 +79,7 @@ > assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD)); > > zipOk(fs.getRoot(), d); >+ fs.close(); > } > > private void zipOk(DirectoryNode root, Decryptor d) throws IOException, GeneralSecurityException { >@@ -86,14 +87,18 @@ > > while (true) { > ZipEntry entry = zin.getNextEntry(); >- if (entry==null) break; >+ if (entry==null) { >+ break; >+ } > // crc32 is checked within zip-stream >- if (entry.isDirectory()) continue; >- zin.skip(entry.getSize()); >+ if (entry.isDirectory()) { >+ continue; >+ } >+ zin.skip(entry.getSize()-1); > byte buf[] = new byte[10]; > int readBytes = zin.read(buf); > // zin.available() doesn't work for entries >- assertEquals("size failed for "+entry.getName(), -1, readBytes); >+ assertEquals("size failed for "+entry.getName(), 1, readBytes); > } > > zin.close(); >@@ -126,10 +131,11 @@ > break; > } > >- while (zin.available()>0) { >- zin.skip(zin.available()); >- } >+ IOUtils.toByteArray(zin); > } >+ >+ is.close(); >+ fs.close(); > } > > @Test >@@ -156,10 +162,13 @@ > > @Test > public void test58616() throws IOException, GeneralSecurityException { >- POIFSFileSystem pfs = new POIFSFileSystem(new FileInputStream(XSSFTestDataSamples.getSampleFile("58616.xlsx"))); >+ FileInputStream fis = new FileInputStream(XSSFTestDataSamples.getSampleFile("58616.xlsx")); >+ POIFSFileSystem pfs = new POIFSFileSystem(fis); > EncryptionInfo info = new EncryptionInfo(pfs); > Decryptor dec = Decryptor.getInstance(info); > //dec.verifyPassword(null); > dec.getDataStream(pfs); >+ pfs.close(); >+ fis.close(); > } > } >\ No newline at end of file >Index: src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java (revision 1753737) >+++ src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java (working copy) >@@ -42,10 +42,10 @@ > import org.apache.poi.poifs.filesystem.Entry; > import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; > import org.apache.poi.poifs.filesystem.POIFSFileSystem; >-import org.apache.poi.util.BoundedInputStream; > import org.apache.poi.util.IOUtils; > import org.apache.poi.util.TempFile; > import org.apache.poi.xwpf.usermodel.XWPFDocument; >+import org.bouncycastle.util.Arrays; > import org.junit.Assume; > import org.junit.Ignore; > import org.junit.Test; >@@ -112,9 +112,10 @@ > assertEquals(decPackLenExpected, payloadExpected.length); > > is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY); >- is = new BoundedInputStream(is, is.available()-16); // ignore padding block > byte encPackExpected[] = IOUtils.toByteArray(is); > is.close(); >+ // ignore padding block >+ encPackExpected = Arrays.copyOf(encPackExpected, encPackExpected.length-16); > > // listDir(nfs.getRoot(), "orig", ""); > >@@ -149,6 +150,7 @@ > > ByteArrayOutputStream bos = new ByteArrayOutputStream(); > fs.writeFilesystem(bos); >+ fs.close(); > > nfs = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray())); > infoActual = new EncryptionInfo(nfs.getRoot()); >@@ -164,8 +166,9 @@ > long decPackLenActual = decActual.getLength(); > > is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY); >- is = new BoundedInputStream(is, is.available()-16); // ignore padding block > byte encPackActual[] = IOUtils.toByteArray(is); >+ // ignore padding block >+ encPackActual = Arrays.copyOf(encPackActual, encPackActual.length-16); > is.close(); > > // listDir(nfs.getRoot(), "copy", ""); >@@ -245,14 +248,10 @@ > > bos.reset(); > fs.writeFilesystem(bos); >+ fs.close(); > > ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); > >- // FileOutputStream fos = new FileOutputStream("encrypted.docx"); >- // IOUtils.copy(bis, fos); >- // fos.close(); >- // bis.reset(); >- > nfs = new NPOIFSFileSystem(bis); > infoExpected = new EncryptionInfo(nfs); > d = Decryptor.getInstance(infoExpected); >@@ -279,6 +278,7 @@ > public void encryptPackageWithoutCoreProperties() throws Exception { > // Open our file without core properties > File inp = POIDataSamples.getOpenXML4JInstance().getFile("OPCCompliance_NoCoreProperties.xlsx"); >+ @SuppressWarnings("resource") > OPCPackage pkg = OPCPackage.open(inp.getPath()); > > // It doesn't have any core properties yet >@@ -295,11 +295,13 @@ > enc.confirmPassword("password"); > OutputStream os = enc.getDataStream(fs); > pkg.save(os); >+ os.close(); > pkg.revert(); > > // Save the resulting OLE2 document, and re-open it > ByteArrayOutputStream baos = new ByteArrayOutputStream(); > fs.writeFilesystem(baos); >+ fs.close(); > > ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); > NPOIFSFileSystem inpFS = new NPOIFSFileSystem(bais); >@@ -316,6 +318,9 @@ > assertNotNull(inpPkg.getPackageProperties()); > assertNotNull(inpPkg.getPackageProperties().getLanguageProperty()); > assertNull(inpPkg.getPackageProperties().getLanguageProperty().getValue()); >+ >+ inpPkg.close(); >+ inpFS.close(); > } > > @Test >@@ -338,7 +343,8 @@ > assertTrue(b); > > // do some strange things with it ;) >- XWPFDocument docx = new XWPFDocument(d.getDataStream(fs)); >+ InputStream docIS = d.getDataStream(fs); >+ XWPFDocument docx = new XWPFDocument(docIS); > docx.getParagraphArray(0).insertNewRun(0).setText("POI was here! All your base are belong to us!"); > docx.getParagraphArray(0).insertNewRun(1).addBreak(); > >@@ -346,6 +352,8 @@ > Encryptor e = encInfo.getEncryptor(); > e.confirmPassword("AYBABTU"); > docx.write(e.getDataStream(fs)); >+ docx.close(); >+ docIS.close(); > > fs.close(); > } >Index: src/resources/devtools/forbidden-signatures.txt >=================================================================== >--- src/resources/devtools/forbidden-signatures.txt (revision 1753737) >+++ src/resources/devtools/forbidden-signatures.txt (working copy) >@@ -109,3 +109,6 @@ > > @defaultMessage Don't interrupt threads use FutureUtils#cancel(Future<T>) instead > java.util.concurrent.Future#cancel(boolean) >+ >+@defaultMessage Don't use ...InputStream.available() as it gives wrong result for certain streams - use IOUtils.toByteArray to read the stream fully and then count the available bytes >+java.io.InputStream#available() >Index: src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java >=================================================================== >--- src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java (revision 1753737) >+++ src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java (working copy) >@@ -53,40 +53,50 @@ > placeableHeader = HwmfPlaceableHeader.readHeader(leis); > header = new HwmfHeader(leis); > >- for (;;) { >- if (leis.available() < 6) { >- logger.log(POILogger.ERROR, "unexpected eof - wmf file was truncated"); >- break; >- } >- // recordSize in DWORDs >- long recordSize = leis.readUInt()*2; >- int recordFunction = leis.readShort(); >- // 4 bytes (recordSize) + 2 bytes (recordFunction) >- int consumedSize = 6; >- HwmfRecordType wrt = HwmfRecordType.getById(recordFunction); >- if (wrt == null) { >- throw new IOException("unexpected record type: "+recordFunction); >- } >- if (wrt == HwmfRecordType.eof) break; >- if (wrt.clazz == null) { >- throw new IOException("unsupported record type: "+recordFunction); >- } >- >- HwmfRecord wr; >- try { >- wr = wrt.clazz.newInstance(); >- records.add(wr); >- } catch (Exception e) { >- throw (IOException)new IOException("can't create wmf record").initCause(e); >- } >- >- consumedSize += wr.init(leis, recordSize, recordFunction); >- int remainingSize = (int)(recordSize - consumedSize); >- assert(remainingSize >= 0); >- if (remainingSize > 0) { >- // skip size in loops, because not always all bytes are skipped in one call >- for (int i=remainingSize; i>0; i-=leis.skip(i)); >+ try { >+ for (;;) { >+ long recordSize; >+ int recordFunction; >+ try { >+ // recordSize in DWORDs >+ recordSize = leis.readUInt()*2; >+ recordFunction = leis.readShort(); >+ } catch (Exception e) { >+ logger.log(POILogger.ERROR, "unexpected eof - wmf file was truncated"); >+ break; >+ } >+ // 4 bytes (recordSize) + 2 bytes (recordFunction) >+ int consumedSize = 6; >+ HwmfRecordType wrt = HwmfRecordType.getById(recordFunction); >+ if (wrt == null) { >+ throw new IOException("unexpected record type: "+recordFunction); >+ } >+ if (wrt == HwmfRecordType.eof) { >+ break; >+ } >+ if (wrt.clazz == null) { >+ throw new IOException("unsupported record type: "+recordFunction); >+ } >+ >+ HwmfRecord wr; >+ try { >+ wr = wrt.clazz.newInstance(); >+ records.add(wr); >+ } catch (Exception e) { >+ throw (IOException)new IOException("can't create wmf record").initCause(e); >+ } >+ >+ consumedSize += wr.init(leis, recordSize, recordFunction); >+ int remainingSize = (int)(recordSize - consumedSize); >+ assert(remainingSize >= 0); >+ if (remainingSize > 0) { >+ // skip size in loops, because not always all bytes are skipped in one call >+ for (int i=remainingSize; i>0; i-=leis.skip(i)); >+ } > } >+ } finally { >+ leis.close(); >+ bis.close(); > } > } > >Index: src/testcases/org/apache/poi/hssf/record/TestObjRecord.java >=================================================================== >--- src/testcases/org/apache/poi/hssf/record/TestObjRecord.java (revision 1753737) >+++ src/testcases/org/apache/poi/hssf/record/TestObjRecord.java (working copy) >@@ -18,21 +18,20 @@ > package org.apache.poi.hssf.record; > > import static org.junit.Assert.assertArrayEquals; >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.assertTrue; >+import static org.junit.Assert.fail; > > import java.util.List; > >-import junit.framework.AssertionFailedError; >-import junit.framework.TestCase; >- > import org.apache.poi.util.HexRead; >+import org.junit.Test; > > /** > * Tests the serialization and deserialization of the ObjRecord class works correctly. > * Test data taken directly from a real Excel file. >- * >- * @author Yegor Kozlov > */ >-public final class TestObjRecord extends TestCase { >+public final class TestObjRecord { > /** > * OBJ record data containing two sub-records. > * The data taken directly from a real Excel file. >@@ -58,6 +57,7 @@ > + "15 00 12 00 00 00 01 00 11 60 00 00 00 00 38 6F CC 03 00 00 00 00 06 00 02 00 00 00 00 00 00 00" > ); > >+ @Test > public void testLoad() { > ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, recdata)); > >@@ -70,6 +70,7 @@ > > } > >+ @Test > public void testStore() { > ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, recdata)); > >@@ -80,6 +81,7 @@ > assertArrayEquals(recdata, subData); > } > >+ @Test > public void testConstruct() { > ObjRecord record = new ObjRecord(); > CommonObjectDataSubRecord ftCmo = new CommonObjectDataSubRecord(); >@@ -106,11 +108,12 @@ > assertTrue( subrecords.get(1) instanceof EndSubRecord ); > } > >+ @Test > public void testReadWriteWithPadding_bug45133() { > ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(recdataNeedingPadding)); > > if (record.getRecordSize() == 34) { >- throw new AssertionFailedError("Identified bug 45133"); >+ fail("Identified bug 45133"); > } > > assertEquals(36, record.getRecordSize()); >@@ -126,6 +129,7 @@ > * Check that ObjRecord tolerates and preserves padding to a 4-byte boundary > * (normally padding is to a 2-byte boundary). > */ >+ @Test > public void test4BytePadding() { > // actual data from file saved by Excel 2007 > byte[] data = HexRead.readFromString("" >Index: src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java >=================================================================== >--- src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java (revision 1753737) >+++ src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java (working copy) >@@ -29,6 +29,7 @@ > import org.apache.poi.poifs.eventfilesystem.POIFSReader; > import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; > import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; >+import org.apache.poi.util.IOUtils; > > /** > * Test (Proof of concept) program that employs the >@@ -40,11 +41,11 @@ > public class ReaderWriter > implements POIFSReaderListener, POIFSWriterListener > { >- private POIFSFileSystem filesystem; >- private DirectoryEntry root; >+ private final POIFSFileSystem filesystem; >+ private final DirectoryEntry root; > > // keys are DocumentDescriptors, values are byte[]s >- private Map<DocumentDescriptor, byte[]> dataMap; >+ private final Map<DocumentDescriptor, byte[]> dataMap; > > /** > * Constructor ReaderWriter >@@ -93,6 +94,8 @@ > > filesystem.writeFilesystem(ostream); > ostream.close(); >+ >+ filesystem.close(); > } > } > >@@ -105,18 +108,18 @@ > * @param event the POIFSReaderEvent > */ > >+ @Override > public void processPOIFSReaderEvent(final POIFSReaderEvent event) > { >+ @SuppressWarnings("resource") > DocumentInputStream istream = event.getStream(); > POIFSDocumentPath path = event.getPath(); > String name = event.getName(); > >- try >- { >- int size = istream.available(); >- byte[] data = new byte[ istream.available() ]; >+ try { >+ byte[] data = IOUtils.toByteArray(istream); >+ int size = data.length; > >- istream.read(data); > DocumentDescriptor descriptor = new DocumentDescriptor(path, > name); > >@@ -167,6 +170,7 @@ > * @param event the POIFSWriterEvent > */ > >+ @Override > public void processPOIFSWriterEvent(final POIFSWriterEvent event) > { > try >Index: src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java >=================================================================== >--- src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java (revision 1753737) >+++ src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java (working copy) >@@ -17,22 +17,28 @@ > > package org.apache.poi.poifs.filesystem; > >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.assertTrue; >+import static org.junit.Assert.fail; >+ > import java.io.ByteArrayInputStream; > import java.io.File; > import java.io.FileInputStream; > import java.io.IOException; >+import java.io.InputStream; > import java.util.Arrays; > >-import junit.framework.TestCase; >- > import org.apache.poi.POIDataSamples; > import org.apache.poi.poifs.property.DirectoryProperty; > import org.apache.poi.poifs.storage.RawDataBlock; >+import org.apache.poi.util.SuppressForbidden; >+import org.junit.Before; >+import org.junit.Test; > > /** > * Class to test DocumentInputStream functionality > */ >-public final class TestDocumentInputStream extends TestCase { >+public final class TestDocumentInputStream { > private DocumentNode _workbook_n; > private DocumentNode _workbook_o; > private byte[] _workbook_data; >@@ -42,7 +48,8 @@ > // any block size > private static final int _buffer_size = 6; > >- protected void setUp() throws Exception { >+ @Before >+ public void setUp() throws Exception { > int blocks = (_workbook_size + 511) / 512; > > _workbook_data = new byte[ 512 * blocks ]; >@@ -91,6 +98,7 @@ > /** > * test constructor > */ >+ @Test > public void testConstructor() throws IOException { > DocumentInputStream ostream = new ODocumentInputStream(_workbook_o); > DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); >@@ -98,8 +106,8 @@ > assertEquals(_workbook_size, _workbook_o.getSize()); > assertEquals(_workbook_size, _workbook_n.getSize()); > >- assertEquals(_workbook_size, ostream.available()); >- assertEquals(_workbook_size, nstream.available()); >+ assertEquals(_workbook_size, available(ostream)); >+ assertEquals(_workbook_size, available(nstream)); > > ostream.close(); > nstream.close(); >@@ -108,23 +116,24 @@ > /** > * test available() behavior > */ >+ @Test > public void testAvailable() throws IOException { > DocumentInputStream ostream = new DocumentInputStream(_workbook_o); > DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); > >- assertEquals(_workbook_size, ostream.available()); >- assertEquals(_workbook_size, nstream.available()); >+ assertEquals(_workbook_size, available(ostream)); >+ assertEquals(_workbook_size, available(nstream)); > ostream.close(); > nstream.close(); > > try { >- ostream.available(); >+ available(ostream); > fail("Should have caught IOException"); > } catch (IllegalStateException ignored) { > // as expected > } > try { >- nstream.available(); >+ available(nstream); > fail("Should have caught IOException"); > } catch (IllegalStateException ignored) { > // as expected >@@ -134,6 +143,7 @@ > /** > * test mark/reset/markSupported. > */ >+ @Test > public void testMarkFunctions() throws IOException { > byte[] buffer = new byte[ _workbook_size / 5 ]; > byte[] small_buffer = new byte[212]; >@@ -151,12 +161,12 @@ > _workbook_data[ j ], buffer[ j ] > ); > } >- assertEquals(_workbook_size - buffer.length, stream.available()); >+ assertEquals(_workbook_size - buffer.length, available(stream)); > > // Reset, and check the available goes back to being the > // whole of the stream > stream.reset(); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > > > // Read part of a block >@@ -167,7 +177,7 @@ > _workbook_data[ j ], small_buffer[ j ] > ); > } >- assertEquals(_workbook_size - small_buffer.length, stream.available()); >+ assertEquals(_workbook_size - small_buffer.length, available(stream)); > stream.mark(0); > > // Read the next part >@@ -178,11 +188,11 @@ > _workbook_data[ j+small_buffer.length ], small_buffer[ j ] > ); > } >- assertEquals(_workbook_size - 2*small_buffer.length, stream.available()); >+ assertEquals(_workbook_size - 2*small_buffer.length, available(stream)); > > // Reset, check it goes back to where it was > stream.reset(); >- assertEquals(_workbook_size - small_buffer.length, stream.available()); >+ assertEquals(_workbook_size - small_buffer.length, available(stream)); > > // Read > stream.read(small_buffer); >@@ -192,7 +202,7 @@ > _workbook_data[ j+small_buffer.length ], small_buffer[ j ] > ); > } >- assertEquals(_workbook_size - 2*small_buffer.length, stream.available()); >+ assertEquals(_workbook_size - 2*small_buffer.length, available(stream)); > > > // Now read at various points >@@ -235,11 +245,11 @@ > _workbook_data[ j ], buffer[ j ] > ); > } >- assertEquals(_workbook_size - buffer.length, stream.available()); >+ assertEquals(_workbook_size - buffer.length, available(stream)); > > // Read all of it again, check it began at the start again > stream.reset(); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > > stream.read(buffer); > for (int j = 0; j < buffer.length; j++) { >@@ -253,7 +263,7 @@ > stream.mark(12); > stream.read(buffer); > assertEquals(_workbook_size - (2 * buffer.length), >- stream.available()); >+ available(stream)); > for (int j = buffer.length; j < (2 * buffer.length); j++) > { > assertEquals("checking byte " + j, _workbook_data[ j ], >@@ -262,12 +272,12 @@ > > // Reset, should go back to only one buffer full read > stream.reset(); >- assertEquals(_workbook_size - buffer.length, stream.available()); >+ assertEquals(_workbook_size - buffer.length, available(stream)); > > // Read the buffer again > stream.read(buffer); > assertEquals(_workbook_size - (2 * buffer.length), >- stream.available()); >+ available(stream)); > for (int j = buffer.length; j < (2 * buffer.length); j++) > { > assertEquals("checking byte " + j, _workbook_data[ j ], >@@ -280,6 +290,7 @@ > /** > * test simple read method > */ >+ @Test > public void testReadSingleByte() throws IOException { > DocumentInputStream[] streams = new DocumentInputStream[] { > new DocumentInputStream(_workbook_o), >@@ -296,7 +307,7 @@ > ( byte ) b); > remaining--; > assertEquals("checking remaining after reading byte " + j, >- remaining, stream.available()); >+ remaining, available(stream)); > } > > // Ensure we fell off the end >@@ -316,6 +327,7 @@ > /** > * Test buffered read > */ >+ @Test > public void testBufferRead() throws IOException { > DocumentInputStream[] streams = new DocumentInputStream[] { > new DocumentInputStream(_workbook_o), >@@ -332,23 +344,22 @@ > > // test reading zero length buffer > assertEquals(0, stream.read(new byte[ 0 ])); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > byte[] buffer = new byte[ _buffer_size ]; > int offset = 0; > >- while (stream.available() >= buffer.length) >+ while (available(stream) >= buffer.length) > { > assertEquals(_buffer_size, stream.read(buffer)); >- for (int j = 0; j < buffer.length; j++) >- { >+ for (byte element : buffer) { > assertEquals("in main loop, byte " + offset, >- _workbook_data[ offset ], buffer[ j ]); >+ _workbook_data[ offset ], element); > offset++; > } > assertEquals("offset " + offset, _workbook_size - offset, >- stream.available()); >+ available(stream)); > } >- assertEquals(_workbook_size % _buffer_size, stream.available()); >+ assertEquals(_workbook_size % _buffer_size, available(stream)); > Arrays.fill(buffer, ( byte ) 0); > int count = stream.read(buffer); > >@@ -378,6 +389,7 @@ > /** > * Test complex buffered read > */ >+ @Test > public void testComplexBufferRead() throws IOException { > DocumentInputStream[] streams = new DocumentInputStream[] { > new DocumentInputStream(_workbook_o), >@@ -413,11 +425,11 @@ > > // test reading zero > assertEquals(0, stream.read(new byte[ 5 ], 0, 0)); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > byte[] buffer = new byte[ _workbook_size ]; > int offset = 0; > >- while (stream.available() >= _buffer_size) >+ while (available(stream) >= _buffer_size) > { > Arrays.fill(buffer, ( byte ) 0); > assertEquals(_buffer_size, >@@ -437,9 +449,9 @@ > } > offset += _buffer_size; > assertEquals("offset " + offset, _workbook_size - offset, >- stream.available()); >+ available(stream)); > } >- assertEquals(_workbook_size % _buffer_size, stream.available()); >+ assertEquals(_workbook_size % _buffer_size, available(stream)); > Arrays.fill(buffer, ( byte ) 0); > int count = stream.read(buffer, offset, > _workbook_size % _buffer_size); >@@ -474,38 +486,40 @@ > /** > * Tests that we can skip within the stream > */ >+ @Test > public void testSkip() throws IOException { > DocumentInputStream[] streams = new DocumentInputStream[] { > new DocumentInputStream(_workbook_o), > new NDocumentInputStream(_workbook_n) > }; > for(DocumentInputStream stream : streams) { >- assertEquals(_workbook_size, stream.available()); >- int count = stream.available(); >+ assertEquals(_workbook_size, available(stream)); >+ int count = available(stream); > >- while (stream.available() >= _buffer_size) { >+ while (available(stream) >= _buffer_size) { > assertEquals(_buffer_size, stream.skip(_buffer_size)); > count -= _buffer_size; >- assertEquals(count, stream.available()); >+ assertEquals(count, available(stream)); > } > assertEquals(_workbook_size % _buffer_size, > stream.skip(_buffer_size)); >- assertEquals(0, stream.available()); >+ assertEquals(0, available(stream)); > stream.reset(); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > assertEquals(_workbook_size, stream.skip(_workbook_size * 2)); >- assertEquals(0, stream.available()); >+ assertEquals(0, available(stream)); > stream.reset(); >- assertEquals(_workbook_size, stream.available()); >+ assertEquals(_workbook_size, available(stream)); > assertEquals(_workbook_size, > stream.skip(2 + ( long ) Integer.MAX_VALUE)); >- assertEquals(0, stream.available()); >+ assertEquals(0, available(stream)); > } > } > > /** > * Test that we can read files at multiple levels down the tree > */ >+ @Test > public void testReadMultipleTreeLevels() throws Exception { > final POIDataSamples _samples = POIDataSamples.getPublisherInstance(); > File sample = _samples.getFile("Sample.pub"); >@@ -551,4 +565,9 @@ > npoifs.close(); > } > } >+ >+ @SuppressForbidden("just for testing") >+ private static int available(InputStream is) throws IOException { >+ return is.available(); >+ } > } >Index: src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java >=================================================================== >--- src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java (revision 1753737) >+++ src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java (working copy) >@@ -23,8 +23,6 @@ > import java.io.InputStream; > import java.nio.ByteBuffer; > >-import junit.framework.TestCase; >- > import org.apache.poi.POIDataSamples; > import org.apache.poi.hssf.HSSFTestDataSamples; > import org.apache.poi.poifs.common.POIFSBigBlockSize; >@@ -33,12 +31,15 @@ > import org.apache.poi.poifs.storage.BlockAllocationTableReader; > import org.apache.poi.poifs.storage.HeaderBlock; > import org.apache.poi.poifs.storage.RawDataBlockList; >+import org.apache.poi.util.IOUtils; >+ >+import junit.framework.TestCase; > > /** > * Tests for the older OPOIFS-based POIFSFileSystem > */ > public final class TestPOIFSFileSystem extends TestCase { >- private POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); >+ private final POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); > > /** > * Mock exception used to ensure correct error handling >@@ -66,14 +67,16 @@ > _isClosed = false; > } > >- public int read() throws IOException { >+ @Override >+ public int read() throws IOException { > int result = _is.read(); > if(result >=0) { > checkRead(1); > } > return result; > } >- public int read(byte[] b, int off, int len) throws IOException { >+ @Override >+ public int read(byte[] b, int off, int len) throws IOException { > int result = _is.read(b, off, len); > checkRead(result); > return result; >@@ -85,7 +88,8 @@ > throw new MyEx(); > } > } >- public void close() throws IOException { >+ @Override >+ public void close() throws IOException { > _isClosed = true; > _is.close(); > } >@@ -139,10 +143,10 @@ > "ShortLastBlock.qwp", "ShortLastBlock.wps" > }; > >- for(int i=0; i<files.length; i++) { >+ for (String file : files) { > // Open the file up > OPOIFSFileSystem fs = new OPOIFSFileSystem( >- _samples.openResourceAsStream(files[i]) >+ _samples.openResourceAsStream(file) > ); > > // Write it into a temp output array >@@ -284,9 +288,7 @@ > DocumentNode doc = (DocumentNode) entry; > DocumentInputStream dis = new DocumentInputStream(doc); > try { >- int numBytes = dis.available(); >- byte[] data = new byte [numBytes]; >- dis.read(data); >+ IOUtils.toByteArray(dis); > } finally { > dis.close(); > } >Index: src/testcases/org/apache/poi/util/TestLittleEndian.java >=================================================================== >--- src/testcases/org/apache/poi/util/TestLittleEndian.java (revision 1753737) >+++ src/testcases/org/apache/poi/util/TestLittleEndian.java (working copy) >@@ -17,25 +17,28 @@ > > package org.apache.poi.util; > >-import junit.framework.TestCase; >-import org.apache.poi.util.LittleEndian.BufferUnderrunException; >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.assertTrue; >+import static org.junit.Assert.fail; > > import java.io.ByteArrayInputStream; > import java.io.IOException; > import java.io.InputStream; > >+import org.apache.poi.util.LittleEndian.BufferUnderrunException; >+import org.junit.Test; >+ > /** > * Class to test LittleEndian functionality >- * >- * @author Marc Johnson > */ >-public final class TestLittleEndian extends TestCase { >+public final class TestLittleEndian { > > /** > * test the getShort() method > */ >+ @Test > public void testGetShort() { >- byte[] testdata = new byte[ LittleEndian.SHORT_SIZE + 1 ]; >+ byte[] testdata = new byte[ LittleEndianConsts.SHORT_SIZE + 1 ]; > > testdata[0] = 0x01; > testdata[1] = (byte) 0xFF; >@@ -48,6 +51,7 @@ > assertEquals(expected[1], LittleEndian.getShort(testdata, 1)); > } > >+ @Test > public void testGetUShort() { > byte[] testdata = { > (byte) 0x01, >@@ -69,7 +73,7 @@ > assertEquals(expected2, LittleEndian.getUShort(testdata2)); > assertEquals(expected3, LittleEndian.getUShort(testdata2, 1)); > >- byte[] testdata3 = new byte[ LittleEndian.SHORT_SIZE + 1 ]; >+ byte[] testdata3 = new byte[ LittleEndianConsts.SHORT_SIZE + 1 ]; > LittleEndian.putUShort(testdata3, 0, expected2); > LittleEndian.putUShort(testdata3, 1, expected3); > assertEquals(testdata3[0], 0x0D); >@@ -94,9 +98,10 @@ > /** > * test the getDouble() method > */ >+ @Test > public void testGetDouble() { > assertEquals(_doubles[0], LittleEndian.getDouble(_double_array, 0), 0.000001 ); >- assertEquals(_doubles[1], LittleEndian.getDouble( _double_array, LittleEndian.DOUBLE_SIZE), 0.000001); >+ assertEquals(_doubles[1], LittleEndian.getDouble( _double_array, LittleEndianConsts.DOUBLE_SIZE), 0.000001); > assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array, 0))); > > double nan = LittleEndian.getDouble(_nan_double_array, 0); >@@ -110,6 +115,7 @@ > /** > * test the getInt() method > */ >+ @Test > public void testGetInt() { > // reading 4 byte data from a 5 byte buffer > byte[] testdata = { >@@ -127,6 +133,7 @@ > /** > * test the getLong method > */ >+ @Test > public void testGetLong() { > > // reading 8 byte values from a 9 byte buffer >@@ -149,26 +156,28 @@ > /** > * test the PutShort method > */ >+ @Test > public void testPutShort() { >- byte[] expected = new byte[ LittleEndian.SHORT_SIZE + 1 ]; >+ byte[] expected = new byte[ LittleEndianConsts.SHORT_SIZE + 1 ]; > > expected[0] = 0x01; > expected[1] = (byte) 0xFF; > expected[2] = 0x02; >- byte[] received = new byte[ LittleEndian.SHORT_SIZE + 1 ]; >+ byte[] received = new byte[ LittleEndianConsts.SHORT_SIZE + 1 ]; > short testdata[] = new short[2]; > > testdata[0] = ( short ) 0xFF01; > testdata[1] = 0x02FF; > LittleEndian.putShort(received, 0, testdata[0]); >- assertTrue(compareByteArrays(received, expected, 0, LittleEndian.SHORT_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 0, LittleEndianConsts.SHORT_SIZE)); > LittleEndian.putShort(received, 1, testdata[1]); >- assertTrue(compareByteArrays(received, expected, 1, LittleEndian.SHORT_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 1, LittleEndianConsts.SHORT_SIZE)); > } > > /** > * test the putInt method > */ >+ @Test > public void testPutInt() { > // writing 4 byte data to a 5 byte buffer > byte[] expected = { >@@ -178,33 +187,35 @@ > (byte) 0xFF, > (byte) 0x02, > }; >- byte[] received = new byte[ LittleEndian.INT_SIZE + 1 ]; >+ byte[] received = new byte[ LittleEndianConsts.INT_SIZE + 1 ]; > > LittleEndian.putInt(received, 0, 0xFFFFFF01); >- assertTrue(compareByteArrays(received, expected, 0, LittleEndian.INT_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 0, LittleEndianConsts.INT_SIZE)); > LittleEndian.putInt(received, 1, 0x02FFFFFF); >- assertTrue(compareByteArrays(received, expected, 1, LittleEndian.INT_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 1, LittleEndianConsts.INT_SIZE)); > } > > /** > * test the putDouble methods > */ >+ @Test > public void testPutDouble() { >- byte[] received = new byte[ LittleEndian.DOUBLE_SIZE + 1 ]; >+ byte[] received = new byte[ LittleEndianConsts.DOUBLE_SIZE + 1 ]; > > LittleEndian.putDouble(received, 0, _doubles[0]); >- assertTrue(compareByteArrays(received, _double_array, 0, LittleEndian.DOUBLE_SIZE)); >+ assertTrue(compareByteArrays(received, _double_array, 0, LittleEndianConsts.DOUBLE_SIZE)); > LittleEndian.putDouble(received, 1, _doubles[1]); >- byte[] expected = new byte[ LittleEndian.DOUBLE_SIZE + 1 ]; >+ byte[] expected = new byte[ LittleEndianConsts.DOUBLE_SIZE + 1 ]; > >- System.arraycopy(_double_array, LittleEndian.DOUBLE_SIZE, expected, >- 1, LittleEndian.DOUBLE_SIZE); >- assertTrue(compareByteArrays(received, expected, 1, LittleEndian.DOUBLE_SIZE)); >+ System.arraycopy(_double_array, LittleEndianConsts.DOUBLE_SIZE, expected, >+ 1, LittleEndianConsts.DOUBLE_SIZE); >+ assertTrue(compareByteArrays(received, expected, 1, LittleEndianConsts.DOUBLE_SIZE)); > } > > /** > * test the putLong method > */ >+ @Test > public void testPutLong() { > // writing 8 byte values to a 9 byte buffer > byte[] expected = { >@@ -218,14 +229,14 @@ > (byte) 0xFF, > (byte) 0x02, > }; >- byte[] received = new byte[ LittleEndian.LONG_SIZE + 1 ]; >+ byte[] received = new byte[ LittleEndianConsts.LONG_SIZE + 1 ]; > > long testdata0 = 0xFFFFFFFFFFFFFF01L; > long testdata1 = 0x02FFFFFFFFFFFFFFL; > LittleEndian.putLong(received, 0, testdata0); >- assertTrue(compareByteArrays(received, expected, 0, LittleEndian.LONG_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 0, LittleEndianConsts.LONG_SIZE)); > LittleEndian.putLong(received, 1, testdata1); >- assertTrue(compareByteArrays(received, expected, 1, LittleEndian.LONG_SIZE)); >+ assertTrue(compareByteArrays(received, expected, 1, LittleEndianConsts.LONG_SIZE)); > } > > private static byte[] _good_array = { >@@ -241,15 +252,20 @@ > /** > * test the readShort method > */ >+ @Test > public void testReadShort() throws IOException { > short expected_value = 0x0201; > InputStream stream = new ByteArrayInputStream(_good_array); > int count = 0; > >- while (stream.available() > 0) { >- short value = LittleEndian.readShort(stream); >- assertEquals(value, expected_value); >- count++; >+ while (true) { >+ try { >+ short value = LittleEndian.readShort(stream); >+ assertEquals(value, expected_value); >+ count++; >+ } catch (BufferUnderrunException e) { >+ break; >+ } > } > assertEquals(count, > _good_array.length / LittleEndianConsts.SHORT_SIZE); >@@ -265,15 +281,20 @@ > /** > * test the readInt method > */ >+ @Test > public void testReadInt() throws IOException { > int expected_value = 0x02010201; > InputStream stream = new ByteArrayInputStream(_good_array); > int count = 0; > >- while (stream.available() > 0) { >- int value = LittleEndian.readInt(stream); >- assertEquals(value, expected_value); >- count++; >+ while (true) { >+ try { >+ int value = LittleEndian.readInt(stream); >+ assertEquals(value, expected_value); >+ count++; >+ } catch (BufferUnderrunException e) { >+ break; >+ } > } > assertEquals(count, _good_array.length / LittleEndianConsts.INT_SIZE); > stream = new ByteArrayInputStream(_bad_array); >@@ -289,15 +310,20 @@ > /** > * test the readLong method > */ >+ @Test > public void testReadLong() throws IOException { > long expected_value = 0x0201020102010201L; > InputStream stream = new ByteArrayInputStream(_good_array); > int count = 0; > >- while (stream.available() > 0) { >- long value = LittleEndian.readLong(stream); >- assertEquals(value, expected_value); >- count++; >+ while (true) { >+ try { >+ long value = LittleEndian.readLong(stream); >+ assertEquals(value, expected_value); >+ count++; >+ } catch (BufferUnderrunException e) { >+ break; >+ } > } > assertEquals(count, > _good_array.length / LittleEndianConsts.LONG_SIZE); >@@ -326,6 +352,7 @@ > // } > // } > >+ @Test > public void testUnsignedByteToInt() { > assertEquals(255, LittleEndian.ubyteToInt((byte)255)); > } >@@ -342,6 +369,7 @@ > return true; > } > >+ @Test > public void testUnsignedShort() { > assertEquals(0xffff, LittleEndian.getUShort(new byte[] { (byte)0xff, (byte)0xff }, 0)); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 59893
:
34067
|
34068
|
34760
|
34761