git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1783347 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_16_FINAL
@@ -126,9 +126,10 @@ public class TreeReaderListener implements POIFSReaderListener | |||
{ | |||
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 | |||
@@ -146,11 +147,7 @@ public class TreeReaderListener implements POIFSReaderListener | |||
} | |||
catch (Exception t) | |||
{ | |||
System.err.println | |||
("Unexpected exception while processing " + | |||
event.getName() + " in " + event.getPath().toString()); | |||
t.printStackTrace(System.err); | |||
throw new RuntimeException(t.getMessage()); | |||
throw new RuntimeException("Unexpected exception while processing " + event.getName() + " in " + event.getPath(), t); | |||
} | |||
is.close(); | |||
@@ -181,9 +178,10 @@ public class TreeReaderListener implements POIFSReaderListener | |||
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 |
@@ -37,6 +37,7 @@ import org.apache.poi.poifs.filesystem.Entry; | |||
import org.apache.poi.util.IOUtils; | |||
import org.apache.poi.util.LittleEndian; | |||
import org.apache.poi.util.LittleEndianConsts; | |||
import org.apache.poi.util.NotImplemented; | |||
/** | |||
* Represents a property set in the Horrible Property Set Format | |||
@@ -419,17 +420,17 @@ public class PropertySet { | |||
*/ | |||
int o = offset; | |||
final int byteOrder = LittleEndian.getUShort(src, o); | |||
o += LittleEndian.SHORT_SIZE; | |||
o += LittleEndianConsts.SHORT_SIZE; | |||
if (byteOrder != BYTE_ORDER_ASSERTION) { | |||
return false; | |||
} | |||
final int format = LittleEndian.getUShort(src, o); | |||
o += LittleEndian.SHORT_SIZE; | |||
o += LittleEndianConsts.SHORT_SIZE; | |||
if (format != 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); | |||
@@ -460,15 +461,15 @@ public class PropertySet { | |||
*/ | |||
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; | |||
o += LittleEndianConsts.INT_SIZE; | |||
if (sectionCount < 0) { | |||
throw new HPSFRuntimeException("Section count " + sectionCount + " is negative."); | |||
} | |||
@@ -492,7 +493,7 @@ public class PropertySet { | |||
*/ | |||
for (int i = 0; i < sectionCount; i++) { | |||
final Section s = new MutableSection(src, o); | |||
o += ClassID.LENGTH + LittleEndian.INT_SIZE; | |||
o += ClassID.LENGTH + LittleEndianConsts.INT_SIZE; | |||
sections.add(s); | |||
} | |||
} | |||
@@ -835,6 +836,8 @@ public class PropertySet { | |||
/** | |||
* @see Object#hashCode() | |||
*/ | |||
@NotImplemented | |||
@Override | |||
public int hashCode() { | |||
throw new UnsupportedOperationException("FIXME: Not yet implemented."); | |||
} | |||
@@ -844,6 +847,7 @@ public class PropertySet { | |||
/** | |||
* @see Object#toString() | |||
*/ | |||
@Override | |||
public String toString() { | |||
final StringBuilder b = new StringBuilder(); | |||
final int sectionCount = getSectionCount(); |
@@ -199,6 +199,7 @@ 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. | |||
@@ -612,7 +613,9 @@ public final class BiffViewer { | |||
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 { | |||
@@ -708,6 +711,7 @@ public final class BiffViewer { | |||
} | |||
@Override | |||
@SuppressForbidden("just delegating the call") | |||
public int available() throws IOException { | |||
return _currentSize - _currentPos + _is.available(); | |||
} |
@@ -58,12 +58,10 @@ public final class ObjRecord extends Record implements Cloneable { | |||
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 | |||
@@ -141,10 +139,9 @@ public final class ObjRecord extends Record implements Cloneable { | |||
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); | |||
sb.append("SUBRECORD: ").append(record.toString()); | |||
} | |||
for (final SubRecord record : subrecords) { | |||
sb.append("SUBRECORD: ").append(record.toString()); | |||
} | |||
} | |||
sb.append("[/OBJ]\n"); | |||
return sb.toString(); | |||
@@ -156,8 +153,7 @@ public final class ObjRecord extends Record implements Cloneable { | |||
return _uninterpretedData.length + 4; | |||
} | |||
int size = 0; | |||
for (int i=subrecords.size()-1; i>=0; i--) { | |||
SubRecord record = subrecords.get(i); | |||
for (SubRecord record : subrecords) { | |||
size += record.getDataSize()+4; | |||
} | |||
if (_isPaddedToQuadByteMultiple) { | |||
@@ -203,6 +199,7 @@ public final class ObjRecord extends Record implements Cloneable { | |||
return sid; | |||
} | |||
// FIXME: return Collections.unmodifiableList? | |||
public List<SubRecord> getSubRecords() { | |||
return subrecords; | |||
} | |||
@@ -223,9 +220,8 @@ public final class ObjRecord extends Record implements Cloneable { | |||
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; | |||
} |
@@ -84,10 +84,12 @@ public abstract class SubRecord { | |||
} | |||
public abstract void serialize(LittleEndianOutput out); | |||
public abstract Object clone(); | |||
@Override | |||
public abstract SubRecord clone(); | |||
/** | |||
* Wether this record terminates the sub-record stream. | |||
* Whether this record terminates the sub-record stream. | |||
* There are two cases when this method must be overridden and return <code>true</code> | |||
* - EndSubRecord (sid = 0x00) | |||
* - LbsDataSubRecord (sid = 0x12) | |||
@@ -109,19 +111,23 @@ public abstract class SubRecord { | |||
in.readFully(buf); | |||
_data = buf; | |||
} | |||
@Override | |||
protected int getDataSize() { | |||
return _data.length; | |||
} | |||
@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; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(64); | |||
StringBuilder sb = new StringBuilder(64); | |||
sb.append(getClass().getName()).append(" ["); | |||
sb.append("sid=").append(HexDump.shortToHex(_sid)); | |||
sb.append(" size=").append(_data.length); |
@@ -76,11 +76,9 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream { | |||
@Override | |||
public int read() throws IOException { | |||
byte[] b = new byte[1]; | |||
if (read(b) == 1) { | |||
return b[0]; | |||
} | |||
return -1; | |||
byte[] b = { 0 }; | |||
// FIXME: compare against -1 or 1? | |||
return (read(b) == -1) ? -1 : b[0]; | |||
} | |||
// do not implement! -> recursion |
@@ -64,6 +64,7 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { | |||
// the cipher can't be final, because for the last chunk we change the padding | |||
// and therefore need to change the cipher too | |||
private Cipher cipher; | |||
private boolean isClosed = false; | |||
public ChunkedCipherOutputStream(DirectoryNode dir, int chunkSize) throws IOException, GeneralSecurityException { | |||
super(null); | |||
@@ -224,6 +225,13 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream { | |||
@Override | |||
public void close() throws IOException { | |||
if (isClosed) { | |||
LOG.log(POILogger.DEBUG, "ChunkedCipherOutputStream was already closed - ignoring"); | |||
return; | |||
} | |||
isClosed = true; | |||
try { | |||
writeChunk(false); | |||
@@ -30,6 +30,7 @@ import org.apache.poi.poifs.filesystem.POIFSDocumentPath; | |||
import org.apache.poi.poifs.property.DirectoryProperty; | |||
import org.apache.poi.poifs.property.Property; | |||
import org.apache.poi.poifs.property.PropertyTable; | |||
import org.apache.poi.poifs.property.RootProperty; | |||
import org.apache.poi.poifs.storage.BlockAllocationTableReader; | |||
import org.apache.poi.poifs.storage.BlockList; | |||
import org.apache.poi.poifs.storage.HeaderBlock; | |||
@@ -94,13 +95,15 @@ public class POIFSReader | |||
new PropertyTable(header_block, data_blocks); | |||
// process documents | |||
RootProperty root = properties.getRoot(); | |||
processProperties(SmallBlockTableReader | |||
.getSmallDocumentBlocks( | |||
header_block.getBigBlockSize(), | |||
data_blocks, properties.getRoot(), | |||
header_block.getSBATStart()), | |||
data_blocks, properties.getRoot() | |||
.getChildren(), new POIFSDocumentPath()); | |||
data_blocks, root, | |||
header_block.getSBATStart() | |||
), | |||
data_blocks, root.getChildren(), new POIFSDocumentPath() | |||
); | |||
} | |||
/** |
@@ -21,6 +21,7 @@ import java.io.IOException; | |||
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 @@ public class DocumentInputStream extends InputStream implements LittleEndianInpu | |||
} | |||
@Override | |||
@SuppressForbidden("just delegating") | |||
public int available() { | |||
return delegate.available(); | |||
} |
@@ -40,13 +40,13 @@ public final class NDocumentInputStream extends DocumentInputStream { | |||
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,6 +97,15 @@ public final class NDocumentInputStream extends DocumentInputStream { | |||
@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"); | |||
} | |||
@@ -146,7 +155,7 @@ public final class NDocumentInputStream extends DocumentInputStream { | |||
if (atEOD()) { | |||
return EOF; | |||
} | |||
int limit = Math.min(available(), len); | |||
int limit = Math.min(remainingBytes(), len); | |||
readFully(b, off, limit); | |||
return limit; | |||
} | |||
@@ -297,13 +306,13 @@ public final class NDocumentInputStream extends DocumentInputStream { | |||
return LittleEndian.getUShort(data); | |||
} | |||
@Override | |||
public int readUByte() { | |||
checkAvaliable(1); | |||
byte[] data = new byte[1]; | |||
readFully(data, 0, 1); | |||
if(data[0] >= 0) | |||
return data[0]; | |||
return data[0] + 256; | |||
} | |||
@Override | |||
public int readUByte() { | |||
checkAvaliable(1); | |||
byte[] data = new byte[1]; | |||
readFully(data, 0, 1); | |||
if (data[0] >= 0) | |||
return data[0]; | |||
return data[0] + 256; | |||
} | |||
} |
@@ -33,13 +33,13 @@ public final class ODocumentInputStream extends DocumentInputStream { | |||
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; |
@@ -26,8 +26,6 @@ import java.io.InputStream; | |||
* | |||
* 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) { | |||
@@ -35,7 +33,8 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
} | |||
@Override | |||
public int available() { | |||
@SuppressForbidden("just delegating") | |||
public int available() { | |||
try { | |||
return super.available(); | |||
} catch (IOException e) { | |||
@@ -44,12 +43,12 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
} | |||
@Override | |||
public byte readByte() { | |||
public byte readByte() { | |||
return (byte)readUByte(); | |||
} | |||
@Override | |||
public int readUByte() { | |||
public int readUByte() { | |||
byte buf[] = new byte[1]; | |||
try { | |||
checkEOF(read(buf), 1); | |||
@@ -60,15 +59,15 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
} | |||
@Override | |||
public double readDouble() { | |||
public double readDouble() { | |||
return Double.longBitsToDouble(readLong()); | |||
} | |||
@Override | |||
public int readInt() { | |||
byte buf[] = new byte[LittleEndianConsts.INT_SIZE]; | |||
public int readInt() { | |||
byte buf[] = new byte[LittleEndianConsts.INT_SIZE]; | |||
try { | |||
checkEOF(read(buf), buf.length); | |||
checkEOF(read(buf), buf.length); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
@@ -82,13 +81,14 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
* @exception RuntimeException | |||
* wraps any IOException thrown from reading the stream. | |||
*/ | |||
//@Override | |||
public long readUInt() { | |||
long retNum = readInt(); | |||
return retNum & 0x00FFFFFFFFL; | |||
} | |||
@Override | |||
public long readLong() { | |||
public long readLong() { | |||
byte buf[] = new byte[LittleEndianConsts.LONG_SIZE]; | |||
try { | |||
checkEOF(read(buf), LittleEndianConsts.LONG_SIZE); | |||
@@ -99,12 +99,12 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
} | |||
@Override | |||
public short readShort() { | |||
public short readShort() { | |||
return (short)readUShort(); | |||
} | |||
@Override | |||
public int readUShort() { | |||
public int readUShort() { | |||
byte buf[] = new byte[LittleEndianConsts.SHORT_SIZE]; | |||
try { | |||
checkEOF(read(buf), LittleEndianConsts.SHORT_SIZE); | |||
@@ -120,19 +120,19 @@ public class LittleEndianInputStream extends FilterInputStream implements Little | |||
} | |||
} | |||
@Override | |||
@Override | |||
public void readFully(byte[] buf) { | |||
readFully(buf, 0, buf.length); | |||
} | |||
readFully(buf, 0, buf.length); | |||
} | |||
@Override | |||
@Override | |||
public void readFully(byte[] buf, int off, int len) { | |||
try { | |||
checkEOF(read(buf, off, len), len); | |||
} catch (IOException e) { | |||
try { | |||
checkEOF(read(buf, off, len), len); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
} | |||
@Override | |||
public void readPlain(byte[] buf, int off, int len) { |
@@ -42,6 +42,7 @@ import org.apache.poi.poifs.common.POIFSConstants; | |||
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 { | |||
/** | |||
@@ -54,7 +55,11 @@ public final class ZipHelper { | |||
* 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.16-beta3, not used anymore | |||
*/ | |||
@Deprecated | |||
@Removal(version="3.18") | |||
public static final int READ_WRITE_FILE_BUFFER_SIZE = 8192; | |||
/** | |||
@@ -74,8 +79,9 @@ public final class ZipHelper { | |||
PackageRelationship corePropsRel = pkg.getRelationshipsByType( | |||
PackageRelationshipTypes.CORE_PROPERTIES).getRelationship(0); | |||
if (corePropsRel == null) | |||
if (corePropsRel == null) { | |||
return null; | |||
} | |||
return new ZipEntry(corePropsRel.getTargetURI().getPath()); | |||
} | |||
@@ -91,8 +97,9 @@ public final class ZipHelper { | |||
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; | |||
} | |||
@@ -106,8 +113,9 @@ public final class ZipHelper { | |||
* @return An OPC compliant name. | |||
*/ | |||
public static String getOPCNameFromZipItemName(String zipItemName) { | |||
if (zipItemName == null) | |||
throw new IllegalArgumentException("zipItemName"); | |||
if (zipItemName == null) { | |||
throw new IllegalArgumentException("zipItemName cannot be null"); | |||
} | |||
if (zipItemName.startsWith(FORWARD_SLASH)) { | |||
return zipItemName; | |||
} | |||
@@ -123,12 +131,14 @@ public final class ZipHelper { | |||
* @return A zip item name without any leading slashes. | |||
*/ | |||
public static String getZipItemNameFromOPCName(String opcItemName) { | |||
if (opcItemName == null) | |||
throw new IllegalArgumentException("opcItemName"); | |||
if (opcItemName == null) { | |||
throw new IllegalArgumentException("opcItemName cannot be null"); | |||
} | |||
String retVal = opcItemName; | |||
while (retVal.startsWith(FORWARD_SLASH)) | |||
while (retVal.startsWith(FORWARD_SLASH)) { | |||
retVal = retVal.substring(1); | |||
} | |||
return retVal; | |||
} | |||
@@ -141,12 +151,14 @@ public final class ZipHelper { | |||
* @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) { |
@@ -44,8 +44,6 @@ import org.w3c.dom.Element; | |||
/** | |||
* 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 final static POILogger logger = POILogFactory.getLogger(ZipPartMarshaller.class); | |||
@@ -56,6 +54,7 @@ public final class ZipPartMarshaller implements PartMarshaller { | |||
* @throws OpenXML4JException | |||
* Throws if an internal exception is thrown. | |||
*/ | |||
@Override | |||
public boolean marshall(PackagePart part, OutputStream os) | |||
throws OpenXML4JException { | |||
if (!(os instanceof ZipOutputStream)) { |
@@ -160,6 +160,7 @@ public class ZipSecureFile extends ZipFile { | |||
* @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); | |||
@@ -170,6 +171,7 @@ public class ZipSecureFile extends ZipFile { | |||
ThresholdInputStream newInner; | |||
if (zipIS instanceof InflaterInputStream) { | |||
newInner = AccessController.doPrivileged(new PrivilegedAction<ThresholdInputStream>() { // NOSONAR | |||
@Override | |||
@SuppressForbidden("TODO: Fix this to not use reflection (it will break in Java 9)! " + | |||
"Better would be to wrap *before* instead of trying to insert wrapper afterwards.") | |||
public ThresholdInputStream run() { | |||
@@ -177,9 +179,9 @@ public class ZipSecureFile extends ZipFile { | |||
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) { | |||
LOG.log(POILogger.WARN, "SecurityManager doesn't allow manipulation via reflection for zipbomb detection - continue with original input stream", ex); | |||
} | |||
@@ -203,24 +205,31 @@ public class ZipSecureFile extends ZipFile { | |||
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 +286,41 @@ public class ZipSecureFile extends ZipFile { | |||
((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); | |||
} |
@@ -50,6 +50,8 @@ public class TestDecryptor { | |||
Decryptor d = Decryptor.getInstance(info); | |||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD)); | |||
fs.close(); | |||
} | |||
@Test | |||
@@ -63,6 +65,8 @@ public class TestDecryptor { | |||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD); | |||
zipOk(fs.getRoot(), d); | |||
fs.close(); | |||
} | |||
@Test | |||
@@ -78,6 +82,8 @@ public class TestDecryptor { | |||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD)); | |||
zipOk(fs.getRoot(), d); | |||
fs.close(); | |||
} | |||
private void zipOk(DirectoryNode root, Decryptor d) throws IOException, GeneralSecurityException { | |||
@@ -85,9 +91,13 @@ public class TestDecryptor { | |||
while (true) { | |||
ZipEntry entry = zin.getNextEntry(); | |||
if (entry==null) break; | |||
if (entry==null) { | |||
break; | |||
} | |||
// crc32 is checked within zip-stream | |||
if (entry.isDirectory()) continue; | |||
if (entry.isDirectory()) { | |||
continue; | |||
} | |||
zin.skip(entry.getSize()); | |||
byte buf[] = new byte[10]; | |||
int readBytes = zin.read(buf); | |||
@@ -182,4 +192,4 @@ public class TestDecryptor { | |||
fs.close(); | |||
} | |||
} | |||
} |