#64350 - Sonar fix - "Iterator.next()" methods should throw "NoSuchElementException"

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1876525 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2020-04-14 19:07:24 +00:00
parent fde6f81305
commit d06de78703
14 changed files with 222 additions and 275 deletions

View File

@ -18,6 +18,7 @@
package org.apache.poi.hssf.record.aggregates; package org.apache.poi.hssf.record.aggregates;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BlankRecord;
@ -338,8 +339,9 @@ public final class ValueRecordsAggregate implements Iterable<CellValueRecordInte
} }
public CellValueRecordInterface next() { public CellValueRecordInterface next() {
if (!hasNext()) if (!hasNext()) {
throw new IndexOutOfBoundsException("iterator has no next"); throw new NoSuchElementException();
}
curRowIndex = nextRowIndex; curRowIndex = nextRowIndex;
curColIndex = nextColIndex; curColIndex = nextColIndex;

View File

@ -29,6 +29,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import org.apache.poi.hpsf.ClassID; import org.apache.poi.hpsf.ClassID;
@ -37,7 +38,7 @@ import org.apache.poi.hpsf.ClassID;
* A DirectoryEntry filter, which exposes another * A DirectoryEntry filter, which exposes another
* DirectoryEntry less certain parts. * DirectoryEntry less certain parts.
* This is typically used when copying or comparing * This is typically used when copying or comparing
* Filesystems. * Filesystems.
*/ */
public class FilteringDirectoryNode implements DirectoryEntry public class FilteringDirectoryNode implements DirectoryEntry
{ {
@ -49,14 +50,14 @@ public class FilteringDirectoryNode implements DirectoryEntry
* Excludes of our child directories * Excludes of our child directories
*/ */
private Map<String,List<String>> childExcludes; private Map<String,List<String>> childExcludes;
private DirectoryEntry directory; private DirectoryEntry directory;
/** /**
* Creates a filter round the specified directory, which * Creates a filter round the specified directory, which
* will exclude entries such as "MyNode" and "MyDir/IgnoreNode". * will exclude entries such as "MyNode" and "MyDir/IgnoreNode".
* The excludes can stretch into children, if they contain a /. * The excludes can stretch into children, if they contain a /.
* *
* @param directory The Directory to filter * @param directory The Directory to filter
* @param excludes The Entries to exclude * @param excludes The Entries to exclude
* @throws IllegalArgumentException if directory is null * @throws IllegalArgumentException if directory is null
@ -66,7 +67,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
throw new IllegalArgumentException("directory cannot be null"); throw new IllegalArgumentException("directory cannot be null");
} }
this.directory = directory; this.directory = directory;
// Process the excludes // Process the excludes
this.excludes = new HashSet<>(); this.excludes = new HashSet<>();
this.childExcludes = new HashMap<>(); this.childExcludes = new HashMap<>();
@ -108,7 +109,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
public Iterator<Entry> iterator() { public Iterator<Entry> iterator() {
return getEntries(); return getEntries();
} }
public int getEntryCount() { public int getEntryCount() {
int size = directory.getEntryCount(); int size = directory.getEntryCount();
for (String excl : excludes) { for (String excl : excludes) {
@ -118,7 +119,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
} }
return size; return size;
} }
public Set<String> getEntryNames() { public Set<String> getEntryNames() {
Set<String> names = new HashSet<>(); Set<String> names = new HashSet<>();
for (String name : directory.getEntryNames()) { for (String name : directory.getEntryNames()) {
@ -144,7 +145,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
if (excludes.contains(name)) { if (excludes.contains(name)) {
throw new FileNotFoundException(name); throw new FileNotFoundException(name);
} }
Entry entry = directory.getEntry(name); Entry entry = directory.getEntry(name);
return wrapEntry(entry); return wrapEntry(entry);
} }
@ -152,7 +153,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
String name = entry.getName(); String name = entry.getName();
if (childExcludes.containsKey(name) && entry instanceof DirectoryEntry) { if (childExcludes.containsKey(name) && entry instanceof DirectoryEntry) {
return new FilteringDirectoryNode( return new FilteringDirectoryNode(
(DirectoryEntry)entry, childExcludes.get(name)); (DirectoryEntry)entry, childExcludes.get(name));
} }
return entry; return entry;
} }
@ -172,7 +173,7 @@ public class FilteringDirectoryNode implements DirectoryEntry
public boolean renameTo(String newName) { public boolean renameTo(String newName) {
return directory.renameTo(newName); return directory.renameTo(newName);
} }
public String getName() { public String getName() {
return directory.getName(); return directory.getName();
} }
@ -188,11 +189,11 @@ public class FilteringDirectoryNode implements DirectoryEntry
public boolean isDocumentEntry() { public boolean isDocumentEntry() {
return false; return false;
} }
private class FilteringIterator implements Iterator<Entry> { private class FilteringIterator implements Iterator<Entry> {
private Iterator<Entry> parent; private Iterator<Entry> parent;
private Entry next; private Entry next;
private FilteringIterator() { private FilteringIterator() {
parent = directory.getEntries(); parent = directory.getEntries();
locateNext(); locateNext();
@ -207,17 +208,21 @@ public class FilteringDirectoryNode implements DirectoryEntry
} }
} }
} }
public boolean hasNext() { public boolean hasNext() {
return (next != null); return (next != null);
} }
public Entry next() { public Entry next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Entry e = next; Entry e = next;
locateNext(); locateNext();
return e; return e;
} }
public void remove() { public void remove() {
throw new UnsupportedOperationException("Remove not supported"); throw new UnsupportedOperationException("Remove not supported");
} }

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.RootProperty; import org.apache.poi.poifs.property.RootProperty;
@ -49,10 +50,10 @@ public class POIFSMiniStore extends BlockStore
this._sbat_blocks = sbats; this._sbat_blocks = sbats;
this._header = header; this._header = header;
this._root = root; this._root = root;
this._mini_stream = new POIFSStream(filesystem, root.getStartBlock()); this._mini_stream = new POIFSStream(filesystem, root.getStartBlock());
} }
/** /**
* Load the block at the given offset. * Load the block at the given offset.
*/ */
@ -61,18 +62,16 @@ public class POIFSMiniStore extends BlockStore
int byteOffset = offset * POIFSConstants.SMALL_BLOCK_SIZE; int byteOffset = offset * POIFSConstants.SMALL_BLOCK_SIZE;
int bigBlockNumber = byteOffset / _filesystem.getBigBlockSize(); int bigBlockNumber = byteOffset / _filesystem.getBigBlockSize();
int bigBlockOffset = byteOffset % _filesystem.getBigBlockSize(); int bigBlockOffset = byteOffset % _filesystem.getBigBlockSize();
// Now locate the data block for it // Now locate the data block for it
Iterator<ByteBuffer> it = _mini_stream.getBlockIterator(); Iterator<ByteBuffer> it = _mini_stream.getBlockIterator();
for(int i=0; i<bigBlockNumber; i++) { for(int i=0; i<bigBlockNumber; i++) {
it.next(); it.next();
} }
ByteBuffer dataBlock = it.next(); ByteBuffer dataBlock = it.next();
if(dataBlock == null) { assert(dataBlock != null);
throw new IndexOutOfBoundsException("Big block " + bigBlockNumber + " outside stream");
}
// Position ourselves, and take a slice // Position ourselves, and take a slice
dataBlock.position( dataBlock.position(
dataBlock.position() + bigBlockOffset dataBlock.position() + bigBlockOffset
); );
@ -80,7 +79,7 @@ public class POIFSMiniStore extends BlockStore
miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE); miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE);
return miniBuffer; return miniBuffer;
} }
/** /**
* Load the block, extending the underlying stream if needed * Load the block, extending the underlying stream if needed
*/ */
@ -89,14 +88,14 @@ public class POIFSMiniStore extends BlockStore
if (_mini_stream.getStartBlock() == POIFSConstants.END_OF_CHAIN) { if (_mini_stream.getStartBlock() == POIFSConstants.END_OF_CHAIN) {
firstInStore = true; firstInStore = true;
} }
// Try to get it without extending the stream // Try to get it without extending the stream
if (! firstInStore) { if (! firstInStore) {
try { try {
return getBlockAt(offset); return getBlockAt(offset);
} catch(IndexOutOfBoundsException e) {} } catch(NoSuchElementException e) {}
} }
// Need to extend the stream // Need to extend the stream
// TODO Replace this with proper append support // TODO Replace this with proper append support
// For now, do the extending by hand... // For now, do the extending by hand...
@ -104,7 +103,7 @@ public class POIFSMiniStore extends BlockStore
// Ask for another block // Ask for another block
int newBigBlock = _filesystem.getFreeBlock(); int newBigBlock = _filesystem.getFreeBlock();
_filesystem.createBlockIfNeeded(newBigBlock); _filesystem.createBlockIfNeeded(newBigBlock);
// If we are the first block to be allocated, initialise the stream // If we are the first block to be allocated, initialise the stream
if (firstInStore) { if (firstInStore) {
_filesystem._get_property_table().getRoot().setStartBlock(newBigBlock); _filesystem._get_property_table().getRoot().setStartBlock(newBigBlock);
@ -123,14 +122,14 @@ public class POIFSMiniStore extends BlockStore
} }
_filesystem.setNextBlock(block, newBigBlock); _filesystem.setNextBlock(block, newBigBlock);
} }
// This is now the new end // This is now the new end
_filesystem.setNextBlock(newBigBlock, POIFSConstants.END_OF_CHAIN); _filesystem.setNextBlock(newBigBlock, POIFSConstants.END_OF_CHAIN);
// Now try again, to get the real small block // Now try again, to get the real small block
return createBlockIfNeeded(offset); return createBlockIfNeeded(offset);
} }
/** /**
* Returns the BATBlock that handles the specified offset, * Returns the BATBlock that handles the specified offset,
* and the relative index within it * and the relative index within it
@ -140,7 +139,7 @@ public class POIFSMiniStore extends BlockStore
offset, _header, _sbat_blocks offset, _header, _sbat_blocks
); );
} }
/** /**
* Works out what block follows the specified one. * Works out what block follows the specified one.
*/ */
@ -148,7 +147,7 @@ public class POIFSMiniStore extends BlockStore
BATBlockAndIndex bai = getBATBlockAndIndex(offset); BATBlockAndIndex bai = getBATBlockAndIndex(offset);
return bai.getBlock().getValueAt( bai.getIndex() ); return bai.getBlock().getValueAt( bai.getIndex() );
} }
/** /**
* Changes the record of what block follows the specified one. * Changes the record of what block follows the specified one.
*/ */
@ -158,7 +157,7 @@ public class POIFSMiniStore extends BlockStore
bai.getIndex(), nextBlock bai.getIndex(), nextBlock
); );
} }
/** /**
* Finds a free block, and returns its offset. * Finds a free block, and returns its offset.
* This method will extend the file if needed, and if doing * This method will extend the file if needed, and if doing
@ -166,7 +165,7 @@ public class POIFSMiniStore extends BlockStore
*/ */
protected int getFreeBlock() throws IOException { protected int getFreeBlock() throws IOException {
int sectorsPerSBAT = _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock(); int sectorsPerSBAT = _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock();
// First up, do we have any spare ones? // First up, do we have any spare ones?
int offset = 0; int offset = 0;
for (BATBlock sbat : _sbat_blocks) { for (BATBlock sbat : _sbat_blocks) {
@ -185,16 +184,16 @@ public class POIFSMiniStore extends BlockStore
// Move onto the next SBAT // Move onto the next SBAT
offset += sectorsPerSBAT; offset += sectorsPerSBAT;
} }
// If we get here, then there aren't any // If we get here, then there aren't any
// free sectors in any of the SBATs // free sectors in any of the SBATs
// So, we need to extend the chain and add another // So, we need to extend the chain and add another
// Create a new BATBlock // Create a new BATBlock
BATBlock newSBAT = BATBlock.createEmptyBATBlock(_filesystem.getBigBlockSizeDetails(), false); BATBlock newSBAT = BATBlock.createEmptyBATBlock(_filesystem.getBigBlockSizeDetails(), false);
int batForSBAT = _filesystem.getFreeBlock(); int batForSBAT = _filesystem.getFreeBlock();
newSBAT.setOurBlockIndex(batForSBAT); newSBAT.setOurBlockIndex(batForSBAT);
// Are we the first SBAT? // Are we the first SBAT?
if(_header.getSBATCount() == 0) { if(_header.getSBATCount() == 0) {
// Tell the header that we've got our first SBAT there // Tell the header that we've got our first SBAT there
@ -212,24 +211,24 @@ public class POIFSMiniStore extends BlockStore
} }
batOffset = nextBat; batOffset = nextBat;
} }
// Add it in at the end // Add it in at the end
_filesystem.setNextBlock(batOffset, batForSBAT); _filesystem.setNextBlock(batOffset, batForSBAT);
// And update the count // And update the count
_header.setSBATBlockCount( _header.setSBATBlockCount(
_header.getSBATCount() + 1 _header.getSBATCount() + 1
); );
} }
// Finish allocating // Finish allocating
_filesystem.setNextBlock(batForSBAT, POIFSConstants.END_OF_CHAIN); _filesystem.setNextBlock(batForSBAT, POIFSConstants.END_OF_CHAIN);
_sbat_blocks.add(newSBAT); _sbat_blocks.add(newSBAT);
// Return our first spot // Return our first spot
return offset; return offset;
} }
@Override @Override
protected ChainLoopDetector getChainLoopDetector() { protected ChainLoopDetector getChainLoopDetector() {
return new ChainLoopDetector( _root.getSize() ); return new ChainLoopDetector( _root.getSize() );
@ -238,7 +237,7 @@ public class POIFSMiniStore extends BlockStore
protected int getBlockStoreBlockSize() { protected int getBlockStoreBlockSize() {
return POIFSConstants.SMALL_BLOCK_SIZE; return POIFSConstants.SMALL_BLOCK_SIZE;
} }
/** /**
* Writes the SBATs to their backing blocks, and updates * Writes the SBATs to their backing blocks, and updates
* the mini-stream size in the properties. Stream size is * the mini-stream size in the properties. Stream size is

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.BlockStore.ChainLoopDetector; import org.apache.poi.poifs.filesystem.BlockStore.ChainLoopDetector;
@ -34,13 +35,13 @@ import org.apache.poi.poifs.storage.HeaderBlock;
* {@link POIFSFileSystem}. It can supply an iterator * {@link POIFSFileSystem}. It can supply an iterator
* to read blocks, and way to write out to existing and * to read blocks, and way to write out to existing and
* new blocks. * new blocks.
* Most users will want a higher level version of this, * Most users will want a higher level version of this,
* which deals with properties to track which stream * which deals with properties to track which stream
* this is. * this is.
* This only works on big block streams, it doesn't * This only works on big block streams, it doesn't
* handle small block ones. * handle small block ones.
* This uses the new NIO code * This uses the new NIO code
* *
* TODO Implement a streaming write method, and append * TODO Implement a streaming write method, and append
*/ */
@ -49,17 +50,17 @@ public class POIFSStream implements Iterable<ByteBuffer>
private BlockStore blockStore; private BlockStore blockStore;
private int startBlock; private int startBlock;
private OutputStream outStream; private OutputStream outStream;
/** /**
* Constructor for an existing stream. It's up to you * Constructor for an existing stream. It's up to you
* to know how to get the start block (eg from a * to know how to get the start block (eg from a
* {@link HeaderBlock} or a {@link Property}) * {@link HeaderBlock} or a {@link Property})
*/ */
public POIFSStream(BlockStore blockStore, int startBlock) { public POIFSStream(BlockStore blockStore, int startBlock) {
this.blockStore = blockStore; this.blockStore = blockStore;
this.startBlock = startBlock; this.startBlock = startBlock;
} }
/** /**
* Constructor for a new stream. A start block won't * Constructor for a new stream. A start block won't
* be allocated until you begin writing to it. * be allocated until you begin writing to it.
@ -68,7 +69,7 @@ public class POIFSStream implements Iterable<ByteBuffer>
this.blockStore = blockStore; this.blockStore = blockStore;
this.startBlock = POIFSConstants.END_OF_CHAIN; this.startBlock = POIFSConstants.END_OF_CHAIN;
} }
/** /**
* What block does this stream start at? * What block does this stream start at?
* Will be {@link POIFSConstants#END_OF_CHAIN} for a * Will be {@link POIFSConstants#END_OF_CHAIN} for a
@ -85,7 +86,7 @@ public class POIFSStream implements Iterable<ByteBuffer>
public Iterator<ByteBuffer> iterator() { public Iterator<ByteBuffer> iterator() {
return getBlockIterator(); return getBlockIterator();
} }
Iterator<ByteBuffer> getBlockIterator() { Iterator<ByteBuffer> getBlockIterator() {
if(startBlock == POIFSConstants.END_OF_CHAIN) { if(startBlock == POIFSConstants.END_OF_CHAIN) {
throw new IllegalStateException( throw new IllegalStateException(
@ -113,11 +114,11 @@ public class POIFSStream implements Iterable<ByteBuffer>
} }
return outStream; return outStream;
} }
// TODO Streaming write support // TODO Streaming write support
// TODO then convert fixed sized write to use streaming internally // TODO then convert fixed sized write to use streaming internally
// TODO Append write support (probably streaming) // TODO Append write support (probably streaming)
/** /**
* Frees all blocks in the stream * Frees all blocks in the stream
*/ */
@ -135,14 +136,14 @@ public class POIFSStream implements Iterable<ByteBuffer>
} }
this.startBlock = POIFSConstants.END_OF_CHAIN; this.startBlock = POIFSConstants.END_OF_CHAIN;
} }
/** /**
* Class that handles a streaming read of one stream * Class that handles a streaming read of one stream
*/ */
protected class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> { protected class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
private ChainLoopDetector loopDetector; private ChainLoopDetector loopDetector;
private int nextBlock; private int nextBlock;
StreamBlockByteBufferIterator(int firstBlock) { StreamBlockByteBufferIterator(int firstBlock) {
this.nextBlock = firstBlock; this.nextBlock = firstBlock;
try { try {
@ -157,10 +158,10 @@ public class POIFSStream implements Iterable<ByteBuffer>
} }
public ByteBuffer next() { public ByteBuffer next() {
if(nextBlock == POIFSConstants.END_OF_CHAIN) { if (!hasNext()) {
throw new IndexOutOfBoundsException("Can't read past the end of the stream"); throw new NoSuchElementException("Can't read past the end of the stream");
} }
try { try {
loopDetector.claim(nextBlock); loopDetector.claim(nextBlock);
ByteBuffer data = blockStore.getBlockAt(nextBlock); ByteBuffer data = blockStore.getBlockAt(nextBlock);
@ -175,7 +176,7 @@ public class POIFSStream implements Iterable<ByteBuffer>
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
protected class StreamBlockByteBuffer extends OutputStream { protected class StreamBlockByteBuffer extends OutputStream {
byte[] oneByte = new byte[1]; byte[] oneByte = new byte[1];
ByteBuffer buffer; ByteBuffer buffer;
@ -192,25 +193,25 @@ public class POIFSStream implements Iterable<ByteBuffer>
void createBlockIfNeeded() throws IOException { void createBlockIfNeeded() throws IOException {
if (buffer != null && buffer.hasRemaining()) return; if (buffer != null && buffer.hasRemaining()) return;
int thisBlock = nextBlock; int thisBlock = nextBlock;
// Allocate a block if needed, otherwise figure // Allocate a block if needed, otherwise figure
// out what the next block will be // out what the next block will be
if(thisBlock == POIFSConstants.END_OF_CHAIN) { if(thisBlock == POIFSConstants.END_OF_CHAIN) {
thisBlock = blockStore.getFreeBlock(); thisBlock = blockStore.getFreeBlock();
loopDetector.claim(thisBlock); loopDetector.claim(thisBlock);
// We're on the end of the chain // We're on the end of the chain
nextBlock = POIFSConstants.END_OF_CHAIN; nextBlock = POIFSConstants.END_OF_CHAIN;
// Mark the previous block as carrying on to us if needed // Mark the previous block as carrying on to us if needed
if(prevBlock != POIFSConstants.END_OF_CHAIN) { if(prevBlock != POIFSConstants.END_OF_CHAIN) {
blockStore.setNextBlock(prevBlock, thisBlock); blockStore.setNextBlock(prevBlock, thisBlock);
} }
blockStore.setNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN); blockStore.setNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN);
// If we've just written the first block on a // If we've just written the first block on a
// new stream, save the start block offset // new stream, save the start block offset
if(startBlock == POIFSConstants.END_OF_CHAIN) { if(startBlock == POIFSConstants.END_OF_CHAIN) {
startBlock = thisBlock; startBlock = thisBlock;
@ -221,7 +222,7 @@ public class POIFSStream implements Iterable<ByteBuffer>
} }
buffer = blockStore.createBlockIfNeeded(thisBlock); buffer = blockStore.createBlockIfNeeded(thisBlock);
// Update pointers // Update pointers
prevBlock = thisBlock; prevBlock = thisBlock;
} }
@ -249,12 +250,12 @@ public class POIFSStream implements Iterable<ByteBuffer>
len -= writeBytes; len -= writeBytes;
} while (len > 0); } while (len > 0);
} }
public void close() throws IOException { public void close() throws IOException {
// If we're overwriting, free any remaining blocks // If we're overwriting, free any remaining blocks
POIFSStream toFree = new POIFSStream(blockStore, nextBlock); POIFSStream toFree = new POIFSStream(blockStore, nextBlock);
toFree.free(loopDetector); toFree.free(loopDetector);
// Mark the end of the stream, if we have any data // Mark the end of the stream, if we have any data
if (prevBlock != POIFSConstants.END_OF_CHAIN) { if (prevBlock != POIFSConstants.END_OF_CHAIN) {
blockStore.setNextBlock(prevBlock, POIFSConstants.END_OF_CHAIN); blockStore.setNextBlock(prevBlock, POIFSConstants.END_OF_CHAIN);

View File

@ -18,6 +18,7 @@
package org.apache.poi.util; package org.apache.poi.util;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
// based on https://gist.github.com/EmmanuelOga/48df70b27ead4d80234b // based on https://gist.github.com/EmmanuelOga/48df70b27ead4d80234b
@Internal @Internal
@ -37,6 +38,9 @@ public class StringCodepointsIterable implements Iterable<String> {
@Override @Override
public String next() { public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int codePoint = StringCodepointsIterable.this.string.codePointAt(index); int codePoint = StringCodepointsIterable.this.string.codePointAt(index);
index += Character.charCount(codePoint); index += Character.charCount(codePoint);
return new String(Character.toChars(codePoint)); return new String(Character.toChars(codePoint));

View File

@ -17,9 +17,10 @@
package org.apache.poi.util; package org.apache.poi.util;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
/** /**
@ -27,7 +28,6 @@ import java.util.Locale;
*/ */
@Internal @Internal
public final class StringUtil { public final class StringUtil {
private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 10000000; private static final int MAX_RECORD_LENGTH = 10000000;
@ -305,38 +305,6 @@ public final class StringUtil {
return haystack.regionMatches(true, start, suffix, 0, length); return haystack.regionMatches(true, start, suffix, 0, length);
} }
/**
* An Iterator over an array of Strings.
*/
public static class StringsIterator implements Iterator<String> {
private String[] strings = {};
private int position;
public StringsIterator(String[] strings) {
if (strings != null) {
this.strings = strings.clone();
}
}
@Override
public boolean hasNext() {
return position < strings.length;
}
@Override
public String next() {
int ourPos = position++;
if (ourPos >= strings.length) {
throw new ArrayIndexOutOfBoundsException(ourPos);
}
return strings[ourPos];
}
@Override
public void remove() {
}
}
@Internal @Internal
public static String toLowerCase(char c) { public static String toLowerCase(char c) {
return Character.toString(c).toLowerCase(Locale.ROOT); return Character.toString(c).toLowerCase(Locale.ROOT);

View File

@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
@ -172,6 +173,9 @@ public class HemfComment {
@Override @Override
public EmfCommentData next() { public EmfCommentData next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
EmfCommentData toReturn = currentRecord; EmfCommentData toReturn = currentRecord;
final boolean isEOF = (limit == -1 || leis.getReadIndex() >= startIdx+limit); final boolean isEOF = (limit == -1 || leis.getReadIndex() >= startIdx+limit);
// (currentRecord instanceof HemfPlusMisc.EmfEof) // (currentRecord instanceof HemfPlusMisc.EmfEof)

View File

@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emf;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
@ -44,6 +45,9 @@ public class HemfRecordIterator implements Iterator<HemfRecord> {
@Override @Override
public HemfRecord next() { public HemfRecord next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
HemfRecord toReturn = currentRecord; HemfRecord toReturn = currentRecord;
currentRecord = (currentRecord instanceof HemfMisc.EmfEof) ? null : _next(); currentRecord = (currentRecord instanceof HemfMisc.EmfEof) ? null : _next();
return toReturn; return toReturn;

View File

@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emfplus;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
@ -49,6 +50,9 @@ public class HemfPlusRecordIterator implements Iterator<HemfPlusRecord> {
@Override @Override
public HemfPlusRecord next() { public HemfPlusRecord next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
HemfPlusRecord toReturn = currentRecord; HemfPlusRecord toReturn = currentRecord;
// add the size for recordId/flags/recordSize/dataSize = 12 bytes // add the size for recordId/flags/recordSize/dataSize = 12 bytes
final boolean isEOF = (limit == -1 || (leis.getReadIndex()-startIdx)+12 > limit); final boolean isEOF = (limit == -1 || (leis.getReadIndex()-startIdx)+12 > limit);

View File

@ -16,6 +16,17 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.hsmf.extractor; package org.apache.poi.hsmf.extractor;
import static org.apache.poi.util.StringUtil.startsWithIgnoreCase;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Locale;
import org.apache.poi.extractor.POIOLE2TextExtractor; import org.apache.poi.extractor.POIOLE2TextExtractor;
import org.apache.poi.hsmf.MAPIMessage; import org.apache.poi.hsmf.MAPIMessage;
import org.apache.poi.hsmf.datatypes.AttachmentChunks; import org.apache.poi.hsmf.datatypes.AttachmentChunks;
@ -24,16 +35,6 @@ import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil.StringsIterator;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Locale;
import static org.apache.poi.util.StringUtil.startsWithIgnoreCase;
/** /**
* A text extractor for HSMF (Outlook) .msg files. * A text extractor for HSMF (Outlook) .msg files.
@ -90,13 +91,11 @@ public class OutlookTextExtractor extends POIOLE2TextExtractor {
msg.guess7BitEncoding(); msg.guess7BitEncoding();
// Off we go // Off we go
StringsIterator emails; Iterator<String> emails;
try { try {
emails = new StringsIterator( emails = Arrays.asList(msg.getRecipientEmailAddressList()).iterator();
msg.getRecipientEmailAddressList()
);
} catch (ChunkNotFoundException e) { } catch (ChunkNotFoundException e) {
emails = new StringsIterator(new String[0]); emails = Collections.emptyIterator();
} }
try { try {
@ -174,7 +173,7 @@ public class OutlookTextExtractor extends POIOLE2TextExtractor {
* of emails, and does its best to return something like * of emails, and does its best to return something like
* "Nick <nick@example.com>; Jim <jim@example.com>" * "Nick <nick@example.com>; Jim <jim@example.com>"
*/ */
protected void handleEmails(StringBuilder s, String type, String displayText, StringsIterator emails) { protected void handleEmails(StringBuilder s, String type, String displayText, Iterator<String> emails) {
if (displayText == null || displayText.length() == 0) { if (displayText == null || displayText.length() == 0) {
return; return;
} }

View File

@ -18,18 +18,23 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
/** /**
* Class to test FilteringDirectoryNode functionality * Class to test FilteringDirectoryNode functionality
*/ */
@ -68,16 +73,20 @@ public final class TestFilteringDirectoryNode {
assertFalse(d.getEntry(eRoot.getName()).isDirectoryEntry()); assertFalse(d.getEntry(eRoot.getName()).isDirectoryEntry());
assertTrue(d.getEntry(eRoot.getName()).isDocumentEntry()); assertTrue(d.getEntry(eRoot.getName()).isDocumentEntry());
Iterator<Entry> i = d.getEntries(); Iterator<Entry> i = d.getEntries();
assertEquals(dirA, i.next()); assertEquals(dirA, i.next());
assertEquals(dirB, i.next()); assertEquals(dirB, i.next());
assertEquals(eRoot, i.next()); assertEquals(eRoot, i.next());
assertNull(i.next()); try {
assertNull(i.next());
fail("Should throw NoSuchElementException when depleted");
} catch (NoSuchElementException ignored) {
}
} }
@Test @Test
public void testChildFiltering() throws Exception { public void testChildFiltering() throws Exception {
List<String> excl = Arrays.asList(new String[]{"NotThere", "AlsoNotThere", eRoot.getName()}); List<String> excl = Arrays.asList("NotThere", "AlsoNotThere", eRoot.getName());
FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl);
assertEquals(2, d.getEntryCount()); assertEquals(2, d.getEntryCount());
@ -96,11 +105,15 @@ public final class TestFilteringDirectoryNode {
Iterator<Entry> i = d.getEntries(); Iterator<Entry> i = d.getEntries();
assertEquals(dirA, i.next()); assertEquals(dirA, i.next());
assertEquals(dirB, i.next()); assertEquals(dirB, i.next());
assertNull(i.next()); try {
assertNull(i.next());
fail("Should throw NoSuchElementException when depleted");
} catch (NoSuchElementException ignored) {
}
// Filter more // Filter more
excl = Arrays.asList(new String[]{"NotThere", "AlsoNotThere", eRoot.getName(), dirA.getName()}); excl = Arrays.asList("NotThere", "AlsoNotThere", eRoot.getName(), dirA.getName());
d = new FilteringDirectoryNode(fs.getRoot(), excl); d = new FilteringDirectoryNode(fs.getRoot(), excl);
assertEquals(1, d.getEntryCount()); assertEquals(1, d.getEntryCount());
@ -122,11 +135,15 @@ public final class TestFilteringDirectoryNode {
i = d.getEntries(); i = d.getEntries();
assertEquals(dirB, i.next()); assertEquals(dirB, i.next());
assertNull(i.next()); try {
assertNull(i.next());
fail("Should throw NoSuchElementException when depleted");
} catch (NoSuchElementException ignored) {
}
// Filter everything // Filter everything
excl = Arrays.asList(new String[]{"NotThere", eRoot.getName(), dirA.getName(), dirB.getName()}); excl = Arrays.asList("NotThere", eRoot.getName(), dirA.getName(), dirB.getName());
d = new FilteringDirectoryNode(fs.getRoot(), excl); d = new FilteringDirectoryNode(fs.getRoot(), excl);
assertEquals(0, d.getEntryCount()); assertEquals(0, d.getEntryCount());
@ -151,17 +168,19 @@ public final class TestFilteringDirectoryNode {
} }
i = d.getEntries(); i = d.getEntries();
assertNull(i.next()); try {
assertNull(i.next());
fail("Should throw NoSuchElementException when depleted");
} catch (NoSuchElementException ignored) {
}
} }
@Test @Test
public void testNestedFiltering() throws Exception { public void testNestedFiltering() throws Exception {
List<String> excl = Arrays.asList(new String[]{ List<String> excl = Arrays.asList(dirA.getName() + "/" + "MadeUp",
dirA.getName() + "/" + "MadeUp", dirA.getName() + "/" + eA.getName(),
dirA.getName() + "/" + eA.getName(), dirA.getName() + "/" + dirAA.getName() + "/Test",
dirA.getName() + "/" + dirAA.getName() + "/Test", eRoot.getName());
eRoot.getName()
});
FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl);
// Check main // Check main

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
@ -38,7 +39,7 @@ import org.junit.Test;
@SuppressWarnings("CatchMayIgnoreException") @SuppressWarnings("CatchMayIgnoreException")
public final class TestPOIFSMiniStore { public final class TestPOIFSMiniStore {
private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance(); private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance();
/** /**
* Check that for a given mini block, we can correctly figure * Check that for a given mini block, we can correctly figure
* out what the next one is * out what the next one is
@ -52,24 +53,24 @@ public final class TestPOIFSMiniStore {
POIFSFileSystem fsD = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); POIFSFileSystem fsD = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB,fsC,fsD}) { for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB,fsC,fsD}) {
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
// 0 -> 51 is one stream // 0 -> 51 is one stream
for(int i=0; i<50; i++) { for(int i=0; i<50; i++) {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
} }
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50));
// 51 -> 103 is the next // 51 -> 103 is the next
for(int i=51; i<103; i++) { for(int i=51; i<103; i++) {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
} }
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(103)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(103));
// Then there are 3 one block ones // Then there are 3 one block ones
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(104)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(104));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(105)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(105));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(106)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(106));
// 107 -> 154 is the next // 107 -> 154 is the next
for(int i=107; i<154; i++) { for(int i=107; i<154; i++) {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
@ -81,32 +82,32 @@ public final class TestPOIFSMiniStore {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
} }
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(160)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(160));
// 161 -> 166 is the next // 161 -> 166 is the next
for(int i=161; i<166; i++) { for(int i=161; i<166; i++) {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
} }
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(166)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(166));
// 167 -> 172 is the next // 167 -> 172 is the next
for(int i=167; i<172; i++) { for(int i=167; i<172; i++) {
assertEquals(i+1, ministore.getNextBlock(i)); assertEquals(i+1, ministore.getNextBlock(i));
} }
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(172)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(172));
// Now some short ones // Now some short ones
assertEquals(174 , ministore.getNextBlock(173)); assertEquals(174 , ministore.getNextBlock(173));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(174)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(174));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(175)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(175));
assertEquals(177 , ministore.getNextBlock(176)); assertEquals(177 , ministore.getNextBlock(176));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(177)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(177));
assertEquals(179 , ministore.getNextBlock(178)); assertEquals(179 , ministore.getNextBlock(178));
assertEquals(180 , ministore.getNextBlock(179)); assertEquals(180 , ministore.getNextBlock(179));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180));
// 181 onwards is free // 181 onwards is free
for(int i=181; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) { for(int i=181; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
@ -131,11 +132,11 @@ public final class TestPOIFSMiniStore {
for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB,fsC,fsD}) { for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB,fsC,fsD}) {
// Mini stream should be at big block zero // Mini stream should be at big block zero
assertEquals(0, fs._get_property_table().getRoot().getStartBlock()); assertEquals(0, fs._get_property_table().getRoot().getStartBlock());
// Grab the ministore // Grab the ministore
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
ByteBuffer b; ByteBuffer b;
// Runs from the start of the data section in 64 byte chungs // Runs from the start of the data section in 64 byte chungs
b = ministore.getBlockAt(0); b = ministore.getBlockAt(0);
assertEquals((byte)0x9e, b.get()); assertEquals((byte)0x9e, b.get());
@ -146,7 +147,7 @@ public final class TestPOIFSMiniStore {
assertEquals((byte)0x21, b.get()); assertEquals((byte)0x21, b.get());
assertEquals((byte)0xd2, b.get()); assertEquals((byte)0xd2, b.get());
assertEquals((byte)0x11, b.get()); assertEquals((byte)0x11, b.get());
// And the next block // And the next block
b = ministore.getBlockAt(1); b = ministore.getBlockAt(1);
assertEquals((byte)0x00, b.get()); assertEquals((byte)0x00, b.get());
@ -157,7 +158,7 @@ public final class TestPOIFSMiniStore {
assertEquals((byte)0x02, b.get()); assertEquals((byte)0x02, b.get());
assertEquals((byte)0x00, b.get()); assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get()); assertEquals((byte)0x00, b.get());
// Check the last data block // Check the last data block
b = ministore.getBlockAt(180); b = ministore.getBlockAt(180);
assertEquals((byte)0x30, b.get()); assertEquals((byte)0x30, b.get());
@ -168,7 +169,7 @@ public final class TestPOIFSMiniStore {
assertEquals((byte)0x00, b.get()); assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get()); assertEquals((byte)0x00, b.get());
assertEquals((byte)0x80, b.get()); assertEquals((byte)0x80, b.get());
// And the rest until the end of the big block is zeros // And the rest until the end of the big block is zeros
for(int i=181; i<184; i++) { for(int i=181; i<184; i++) {
b = ministore.getBlockAt(i); b = ministore.getBlockAt(i);
@ -187,7 +188,7 @@ public final class TestPOIFSMiniStore {
fsB.close(); fsB.close();
fsA.close(); fsA.close();
} }
/** /**
* Ask for free blocks where there are some already * Ask for free blocks where there are some already
* to be had from the SFAT * to be had from the SFAT
@ -196,27 +197,27 @@ public final class TestPOIFSMiniStore {
public void testGetFreeBlockWithSpare() throws Exception { public void testGetFreeBlockWithSpare() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
// Our 2nd SBAT block has spares // Our 2nd SBAT block has spares
assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
assertTrue(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertTrue(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
// First free one at 181 // First free one at 181
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(181)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(181));
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(182)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(182));
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(183)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(183));
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(184)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(184));
// Ask, will get 181 // Ask, will get 181
assertEquals(181, ministore.getFreeBlock()); assertEquals(181, ministore.getFreeBlock());
// Ask again, will still get 181 as not written to // Ask again, will still get 181 as not written to
assertEquals(181, ministore.getFreeBlock()); assertEquals(181, ministore.getFreeBlock());
// Allocate it, then ask again // Allocate it, then ask again
ministore.setNextBlock(181, POIFSConstants.END_OF_CHAIN); ministore.setNextBlock(181, POIFSConstants.END_OF_CHAIN);
assertEquals(182, ministore.getFreeBlock()); assertEquals(182, ministore.getFreeBlock());
fs.close(); fs.close();
} }
@ -228,21 +229,21 @@ public final class TestPOIFSMiniStore {
public void testGetFreeBlockWithNoneSpare() throws Exception { public void testGetFreeBlockWithNoneSpare() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
// We've spare ones from 181 to 255 // We've spare ones from 181 to 255
for(int i=181; i<256; i++) { for(int i=181; i<256; i++) {
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
} }
// Check our SBAT free stuff is correct // Check our SBAT free stuff is correct
assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
assertTrue(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertTrue(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
// Allocate all the spare ones // Allocate all the spare ones
for(int i=181; i<256; i++) { for(int i=181; i<256; i++) {
ministore.setNextBlock(i, POIFSConstants.END_OF_CHAIN); ministore.setNextBlock(i, POIFSConstants.END_OF_CHAIN);
} }
// SBAT are now full, but there's only the two // SBAT are now full, but there's only the two
assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
assertFalse(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
@ -250,30 +251,30 @@ public final class TestPOIFSMiniStore {
assertFalse(ministore.getBATBlockAndIndex(256).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(256).getBlock().hasFreeSectors());
fail("Should only be two SBATs"); fail("Should only be two SBATs");
} catch(IndexOutOfBoundsException e) {} } catch(IndexOutOfBoundsException e) {}
// Now ask for a free one, will need to extend the SBAT chain // Now ask for a free one, will need to extend the SBAT chain
assertEquals(256, ministore.getFreeBlock()); assertEquals(256, ministore.getFreeBlock());
assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
assertFalse(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertFalse(ministore.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
assertTrue(ministore.getBATBlockAndIndex(256).getBlock().hasFreeSectors()); assertTrue(ministore.getBATBlockAndIndex(256).getBlock().hasFreeSectors());
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(254)); // 2nd SBAT assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(254)); // 2nd SBAT
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(255)); // 2nd SBAT assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(255)); // 2nd SBAT
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(256)); // 3rd SBAT assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(256)); // 3rd SBAT
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(257)); // 3rd SBAT assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(257)); // 3rd SBAT
fs.close(); fs.close();
} }
/** /**
* Test that we will extend the underlying chain of * Test that we will extend the underlying chain of
* big blocks that make up the ministream as needed * big blocks that make up the ministream as needed
*/ */
@Test @Test
public void testCreateBlockIfNeeded() throws Exception { public void testCreateBlockIfNeeded() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
// 178 -> 179 -> 180, 181+ is free // 178 -> 179 -> 180, 181+ is free
assertEquals(179 , ministore.getNextBlock(178)); assertEquals(179 , ministore.getNextBlock(178));
assertEquals(180 , ministore.getNextBlock(179)); assertEquals(180 , ministore.getNextBlock(179));
@ -281,7 +282,7 @@ public final class TestPOIFSMiniStore {
for(int i=181; i<256; i++) { for(int i=181; i<256; i++) {
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
} }
// However, the ministore data only covers blocks to 183 // However, the ministore data only covers blocks to 183
for(int i=0; i<=183; i++) { for(int i=0; i<=183; i++) {
ministore.getBlockAt(i); ministore.getBlockAt(i);
@ -289,8 +290,8 @@ public final class TestPOIFSMiniStore {
try { try {
ministore.getBlockAt(184); ministore.getBlockAt(184);
fail("No block at 184"); fail("No block at 184");
} catch(IndexOutOfBoundsException e) {} } catch(NoSuchElementException e) {}
// The ministore itself is made up of 23 big blocks // The ministore itself is made up of 23 big blocks
Iterator<ByteBuffer> it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); Iterator<ByteBuffer> it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator();
int count = 0; int count = 0;
@ -299,10 +300,10 @@ public final class TestPOIFSMiniStore {
it.next(); it.next();
} }
assertEquals(23, count); assertEquals(23, count);
// Ask it to get block 184 with creating, it will do // Ask it to get block 184 with creating, it will do
ministore.createBlockIfNeeded(184); ministore.createBlockIfNeeded(184);
// The ministore should be one big block bigger now // The ministore should be one big block bigger now
it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); it = new POIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator();
count = 0; count = 0;
@ -311,7 +312,7 @@ public final class TestPOIFSMiniStore {
it.next(); it.next();
} }
assertEquals(24, count); assertEquals(24, count);
// The mini block block counts now run to 191 // The mini block block counts now run to 191
for(int i=0; i<=191; i++) { for(int i=0; i<=191; i++) {
ministore.getBlockAt(i); ministore.getBlockAt(i);
@ -319,14 +320,14 @@ public final class TestPOIFSMiniStore {
try { try {
ministore.getBlockAt(192); ministore.getBlockAt(192);
fail("No block at 192"); fail("No block at 192");
} catch(IndexOutOfBoundsException e) {} } catch(NoSuchElementException e) {}
// Now try writing through to 192, check that the SBAT and blocks are there // Now try writing through to 192, check that the SBAT and blocks are there
byte[] data = new byte[15*64]; byte[] data = new byte[15*64];
POIFSStream stream = new POIFSStream(ministore, 178); POIFSStream stream = new POIFSStream(ministore, 178);
stream.updateContents(data); stream.updateContents(data);
// Check now // Check now
assertEquals(179 , ministore.getNextBlock(178)); assertEquals(179 , ministore.getNextBlock(178));
assertEquals(180 , ministore.getNextBlock(179)); assertEquals(180 , ministore.getNextBlock(179));
@ -346,10 +347,10 @@ public final class TestPOIFSMiniStore {
for(int i=193; i<256; i++) { for(int i=193; i<256; i++) {
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i));
} }
fs.close(); fs.close();
} }
@Test @Test
public void testCreateMiniStoreFirst() throws Exception { public void testCreateMiniStoreFirst() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(); POIFSFileSystem fs = new POIFSFileSystem();
@ -365,14 +366,14 @@ public final class TestPOIFSMiniStore {
try { try {
ministore.getNextBlock(0); ministore.getNextBlock(0);
} catch (IndexOutOfBoundsException e) {} } catch (IndexOutOfBoundsException e) {}
// Write a very small new document, will populate the ministore for us // Write a very small new document, will populate the ministore for us
byte[] data = new byte[8]; byte[] data = new byte[8];
for (int i=0; i<data.length; i++) { for (int i=0; i<data.length; i++) {
data[i] = (byte)(i+42); data[i] = (byte)(i+42);
} }
fs.getRoot().createDocument("mini", new ByteArrayInputStream(data)); fs.getRoot().createDocument("mini", new ByteArrayInputStream(data));
// Should now have a mini-fat and a mini-stream // Should now have a mini-fat and a mini-stream
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,fs.getNextBlock(1)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,fs.getNextBlock(1));
@ -381,11 +382,11 @@ public final class TestPOIFSMiniStore {
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(0));
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(1)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(1));
// Re-fetch the mini store, and add it a second time // Re-fetch the mini store, and add it a second time
ministore = fs.getMiniStore(); ministore = fs.getMiniStore();
fs.getRoot().createDocument("mini2", new ByteArrayInputStream(data)); fs.getRoot().createDocument("mini2", new ByteArrayInputStream(data));
// Main unchanged, ministore has a second // Main unchanged, ministore has a second
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,fs.getNextBlock(1)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,fs.getNextBlock(1));
@ -395,7 +396,7 @@ public final class TestPOIFSMiniStore {
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(0));
assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(1)); assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(1));
assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(2)); assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(2));
// Check the data is unchanged and the right length // Check the data is unchanged and the right length
entry = (DocumentEntry)fs.getRoot().getEntry("mini"); entry = (DocumentEntry)fs.getRoot().getEntry("mini");
assertEquals(data.length, entry.getSize()); assertEquals(data.length, entry.getSize());
@ -404,7 +405,7 @@ public final class TestPOIFSMiniStore {
IOUtils.readFully(dis, rdata); IOUtils.readFully(dis, rdata);
assertArrayEquals(data, rdata); assertArrayEquals(data, rdata);
dis.close(); dis.close();
entry = (DocumentEntry)fs.getRoot().getEntry("mini2"); entry = (DocumentEntry)fs.getRoot().getEntry("mini2");
assertEquals(data.length, entry.getSize()); assertEquals(data.length, entry.getSize());
rdata = new byte[data.length]; rdata = new byte[data.length];
@ -416,7 +417,7 @@ public final class TestPOIFSMiniStore {
// Done // Done
fs.close(); fs.close();
} }
@Test @Test
public void testMultiBlockStream() throws Exception { public void testMultiBlockStream() throws Exception {
byte[] data1B = new byte[63]; byte[] data1B = new byte[63];
@ -427,7 +428,7 @@ public final class TestPOIFSMiniStore {
for (int i=0; i<data2B.length; i++) { for (int i=0; i<data2B.length; i++) {
data2B[i] = (byte)(i+4); data2B[i] = (byte)(i+4);
} }
// New filesystem and store to use // New filesystem and store to use
POIFSFileSystem fs = new POIFSFileSystem(); POIFSFileSystem fs = new POIFSFileSystem();
@ -435,41 +436,41 @@ public final class TestPOIFSMiniStore {
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1));
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(2)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(2));
// Store the 2 block one, should use 2 mini blocks, and request // Store the 2 block one, should use 2 mini blocks, and request
// the use of 2 big blocks // the use of 2 big blocks
POIFSMiniStore ministore = fs.getMiniStore(); POIFSMiniStore ministore = fs.getMiniStore();
fs.getRoot().createDocument("mini2", new ByteArrayInputStream(data2B)); fs.getRoot().createDocument("mini2", new ByteArrayInputStream(data2B));
// Check // Check
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1));
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // SBAT assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // SBAT
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3)); // Mini assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3)); // Mini
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4));
// First 2 Mini blocks will be used // First 2 Mini blocks will be used
assertEquals(2, ministore.getFreeBlock()); assertEquals(2, ministore.getFreeBlock());
// Add one more mini-stream, and check // Add one more mini-stream, and check
fs.getRoot().createDocument("mini1", new ByteArrayInputStream(data1B)); fs.getRoot().createDocument("mini1", new ByteArrayInputStream(data1B));
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0)); assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(1));
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // SBAT assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); // SBAT
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3)); // Mini assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(3)); // Mini
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(4));
// One more mini-block will be used // One more mini-block will be used
assertEquals(3, ministore.getFreeBlock()); assertEquals(3, ministore.getFreeBlock());
// Check the contents too // Check the contents too
byte[] r1 = new byte[data1B.length]; byte[] r1 = new byte[data1B.length];
DocumentInputStream dis = fs.createDocumentInputStream("mini1"); DocumentInputStream dis = fs.createDocumentInputStream("mini1");
IOUtils.readFully(dis, r1); IOUtils.readFully(dis, r1);
dis.close(); dis.close();
assertArrayEquals(data1B, r1); assertArrayEquals(data1B, r1);
byte[] r2 = new byte[data2B.length]; byte[] r2 = new byte[data2B.length];
dis = fs.createDocumentInputStream("mini2"); dis = fs.createDocumentInputStream("mini2");
IOUtils.readFully(dis, r2); IOUtils.readFully(dis, r2);

View File

@ -36,6 +36,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.DocumentSummaryInformation;
@ -72,12 +73,8 @@ public final class TestPOIFSStream {
POIFSStream stream = new POIFSStream(fs, 98); POIFSStream stream = new POIFSStream(fs, 98);
Iterator<ByteBuffer> i = stream.getBlockIterator(); Iterator<ByteBuffer> i = stream.getBlockIterator();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b = i.next(); ByteBuffer b = i.next();
assertFalse(i.hasNext()); assertFalse(i.hasNext());
assertFalse(i.hasNext());
assertFalse(i.hasNext());
// Check the contents // Check the contents
assertEquals((byte)0x81, b.get()); assertEquals((byte)0x81, b.get());
@ -103,15 +100,10 @@ public final class TestPOIFSStream {
POIFSStream stream = new POIFSStream(fs, 97); POIFSStream stream = new POIFSStream(fs, 97);
Iterator<ByteBuffer> i = stream.getBlockIterator(); Iterator<ByteBuffer> i = stream.getBlockIterator();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b97 = i.next(); ByteBuffer b97 = i.next();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b98 = i.next(); ByteBuffer b98 = i.next();
assertFalse(i.hasNext()); assertFalse(i.hasNext());
assertFalse(i.hasNext());
assertFalse(i.hasNext());
// Check the contents of the 1st block // Check the contents of the 1st block
assertEquals((byte)0x01, b97.get()); assertEquals((byte)0x01, b97.get());
@ -169,18 +161,21 @@ public final class TestPOIFSStream {
// Check the contents // Check the contents
// 1st block is at 0 // 1st block is at 0
assertNotNull(b0);
assertEquals((byte)0x9e, b0.get()); assertEquals((byte)0x9e, b0.get());
assertEquals((byte)0x75, b0.get()); assertEquals((byte)0x75, b0.get());
assertEquals((byte)0x97, b0.get()); assertEquals((byte)0x97, b0.get());
assertEquals((byte)0xf6, b0.get()); assertEquals((byte)0xf6, b0.get());
// 2nd block is at 1 // 2nd block is at 1
assertNotNull(b1);
assertEquals((byte)0x86, b1.get()); assertEquals((byte)0x86, b1.get());
assertEquals((byte)0x09, b1.get()); assertEquals((byte)0x09, b1.get());
assertEquals((byte)0x22, b1.get()); assertEquals((byte)0x22, b1.get());
assertEquals((byte)0xfb, b1.get()); assertEquals((byte)0xfb, b1.get());
// last block is at 89 // last block is at 89
assertNotNull(b22);
assertEquals((byte)0xfe, b22.get()); assertEquals((byte)0xfe, b22.get());
assertEquals((byte)0xff, b22.get()); assertEquals((byte)0xff, b22.get());
assertEquals((byte)0x00, b22.get()); assertEquals((byte)0x00, b22.get());
@ -204,18 +199,12 @@ public final class TestPOIFSStream {
POIFSStream stream = new POIFSStream(fs, 0); POIFSStream stream = new POIFSStream(fs, 0);
Iterator<ByteBuffer> i = stream.getBlockIterator(); Iterator<ByteBuffer> i = stream.getBlockIterator();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b0 = i.next(); ByteBuffer b0 = i.next();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b1 = i.next(); ByteBuffer b1 = i.next();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b2 = i.next(); ByteBuffer b2 = i.next();
assertFalse(i.hasNext()); assertFalse(i.hasNext());
assertFalse(i.hasNext());
assertFalse(i.hasNext());
// Check the contents of the 1st block // Check the contents of the 1st block
assertEquals((byte)0x9E, b0.get()); assertEquals((byte)0x9E, b0.get());
@ -304,17 +293,12 @@ public final class TestPOIFSStream {
POIFSStream stream = new POIFSStream(ministore, 178); POIFSStream stream = new POIFSStream(ministore, 178);
Iterator<ByteBuffer> i = stream.getBlockIterator(); Iterator<ByteBuffer> i = stream.getBlockIterator();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b178 = i.next(); ByteBuffer b178 = i.next();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
assertTrue(i.hasNext());
ByteBuffer b179 = i.next(); ByteBuffer b179 = i.next();
assertTrue(i.hasNext()); assertTrue(i.hasNext());
ByteBuffer b180 = i.next(); ByteBuffer b180 = i.next();
assertFalse(i.hasNext()); assertFalse(i.hasNext());
assertFalse(i.hasNext());
assertFalse(i.hasNext());
// Check the contents of the 1st block // Check the contents of the 1st block
assertEquals((byte)0xfe, b178.get()); assertEquals((byte)0xfe, b178.get());
@ -803,7 +787,7 @@ public final class TestPOIFSStream {
try { try {
ministore.getBlockAt(184); ministore.getBlockAt(184);
fail("Block 184 should be off the end of the list"); fail("Block 184 should be off the end of the list");
} catch (IndexOutOfBoundsException e) { } catch (NoSuchElementException e) {
} }
data = new byte[64 * 6 + 12]; data = new byte[64 * 6 + 12];

View File

@ -24,7 +24,6 @@ import static org.junit.Assert.fail;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import org.apache.poi.util.StringUtil.StringsIterator;
import org.junit.Test; import org.junit.Test;
/** /**
@ -127,52 +126,6 @@ public class TestStringUtil {
} }
} }
@Test
public void testStringsIterator() {
StringsIterator i;
i = new StringsIterator(new String[0]);
assertFalse(i.hasNext());
try {
i.next();
fail();
} catch(ArrayIndexOutOfBoundsException e) {
// expected here
}
i = new StringsIterator(new String[] {"1"});
assertTrue(i.hasNext());
assertEquals("1", i.next());
assertFalse(i.hasNext());
try {
i.next();
fail();
} catch(ArrayIndexOutOfBoundsException e) {
// expected here
}
i = new StringsIterator(new String[] {"1","2","3"});
assertTrue(i.hasNext());
assertEquals("1", i.next());
assertTrue(i.hasNext());
assertEquals("2", i.next());
assertTrue(i.hasNext());
assertEquals("3", i.next());
assertFalse(i.hasNext());
try {
i.next();
fail();
} catch(ArrayIndexOutOfBoundsException e) {
// expected here
}
}
@Test @Test
public void startsWithIgnoreCase() { public void startsWithIgnoreCase() {
assertTrue("same string", StringUtil.startsWithIgnoreCase("Apache POI", "Apache POI")); assertTrue("same string", StringUtil.startsWithIgnoreCase("Apache POI", "Apache POI"));
@ -181,7 +134,7 @@ public class TestStringUtil {
assertFalse("leading whitespace should not be ignored", StringUtil.startsWithIgnoreCase(" Apache POI project", "Apache POI")); assertFalse("leading whitespace should not be ignored", StringUtil.startsWithIgnoreCase(" Apache POI project", "Apache POI"));
assertFalse("shorter string", StringUtil.startsWithIgnoreCase("Apache", "Apache POI")); assertFalse("shorter string", StringUtil.startsWithIgnoreCase("Apache", "Apache POI"));
} }
@Test @Test
public void endsWithIgnoreCase() { public void endsWithIgnoreCase() {
assertTrue("same string", StringUtil.endsWithIgnoreCase("Apache POI", "Apache POI")); assertTrue("same string", StringUtil.endsWithIgnoreCase("Apache POI", "Apache POI"));
@ -190,34 +143,34 @@ public class TestStringUtil {
assertFalse("trailing whitespace should not be ignored", StringUtil.endsWithIgnoreCase("Apache POI project ", "Apache POI")); assertFalse("trailing whitespace should not be ignored", StringUtil.endsWithIgnoreCase("Apache POI project ", "Apache POI"));
assertFalse("shorter string", StringUtil.endsWithIgnoreCase("Apache", "Apache POI")); assertFalse("shorter string", StringUtil.endsWithIgnoreCase("Apache", "Apache POI"));
} }
@Test @Test
public void join() { public void join() {
assertEquals("", StringUtil.join(",")); // degenerate case: nothing to join assertEquals("", StringUtil.join(",")); // degenerate case: nothing to join
assertEquals("abc", StringUtil.join(",", "abc")); // degenerate case: one thing to join, no trailing comma assertEquals("abc", StringUtil.join(",", "abc")); // degenerate case: one thing to join, no trailing comma
assertEquals("abc|def|ghi", StringUtil.join("|", "abc", "def", "ghi")); assertEquals("abc|def|ghi", StringUtil.join("|", "abc", "def", "ghi"));
assertEquals("5|8.5|true|string", StringUtil.join("|", 5, 8.5, true, "string")); //assumes Locale prints number decimal point as a period rather than a comma assertEquals("5|8.5|true|string", StringUtil.join("|", 5, 8.5, true, "string")); //assumes Locale prints number decimal point as a period rather than a comma
String[] arr = new String[] { "Apache", "POI", "project" }; String[] arr = new String[] { "Apache", "POI", "project" };
assertEquals("no separator", "ApachePOIproject", StringUtil.join(arr)); assertEquals("no separator", "ApachePOIproject", StringUtil.join(arr));
assertEquals("separator", "Apache POI project", StringUtil.join(arr, " ")); assertEquals("separator", "Apache POI project", StringUtil.join(arr, " "));
} }
@Test @Test
public void count() { public void count() {
String test = "Apache POI project\n\u00a9 Copyright 2016"; String test = "Apache POI project\n\u00a9 Copyright 2016";
// supports search in null or empty string // supports search in null or empty string
assertEquals("null", 0, StringUtil.countMatches(null, 'A')); assertEquals("null", 0, StringUtil.countMatches(null, 'A'));
assertEquals("empty string", 0, StringUtil.countMatches("", 'A')); assertEquals("empty string", 0, StringUtil.countMatches("", 'A'));
assertEquals("normal", 2, StringUtil.countMatches(test, 'e')); assertEquals("normal", 2, StringUtil.countMatches(test, 'e'));
assertEquals("normal, should not find a in escaped copyright", 1, StringUtil.countMatches(test, 'a')); assertEquals("normal, should not find a in escaped copyright", 1, StringUtil.countMatches(test, 'a'));
// search for non-printable characters // search for non-printable characters
assertEquals("null character", 0, StringUtil.countMatches(test, '\0')); assertEquals("null character", 0, StringUtil.countMatches(test, '\0'));
assertEquals("CR", 0, StringUtil.countMatches(test, '\r')); assertEquals("CR", 0, StringUtil.countMatches(test, '\r'));
assertEquals("LF", 1, StringUtil.countMatches(test, '\n')); assertEquals("LF", 1, StringUtil.countMatches(test, '\n'));
// search for unicode characters // search for unicode characters
assertEquals("Unicode", 1, StringUtil.countMatches(test, '\u00a9')); assertEquals("Unicode", 1, StringUtil.countMatches(test, '\u00a9'));
} }