diff options
Diffstat (limited to 'src/java')
12 files changed, 275 insertions, 118 deletions
diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index cb17d84b56..631be8fd2d 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -527,20 +527,16 @@ public final class BiffViewer { } @Override public int read(byte[] b, int off, int len) throws IOException { + if (b == null || off < 0 || len < 0 || b.length < off+len) { + throw new IllegalArgumentException(); + } if (_currentPos >= _currentSize) { fillNextBuffer(); } if (_currentPos >= _currentSize) { return -1; } - int availSize = _currentSize - _currentPos; - int result; - if (len > availSize) { - System.err.println("Unexpected request to read past end of current biff record"); - result = availSize; - } else { - result = len; - } + final int result = Math.min(len, _currentSize - _currentPos); System.arraycopy(_data, _currentPos, b, off, result); _currentPos += result; _overallStreamPos += result; diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java index 8347655a81..400553721e 100644 --- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java +++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java @@ -106,8 +106,8 @@ public final class RecordInputStream implements LittleEndianInput { private final LittleEndianInput _lei; - public SimpleHeaderInput(InputStream in) { - _lei = getLEI(in); + private SimpleHeaderInput(LittleEndianInput lei) { + _lei = lei; } @Override public int available() { @@ -129,8 +129,12 @@ public final class RecordInputStream implements LittleEndianInput { public RecordInputStream(InputStream in, EncryptionInfo key, int initialOffset) throws RecordFormatException { if (key == null) { - _dataInput = getLEI(in); - _bhi = new SimpleHeaderInput(in); + _dataInput = (in instanceof LittleEndianInput) + // accessing directly is an optimisation + ? (LittleEndianInput)in + // less optimal, but should work OK just the same. Often occurs in junit tests. + : new LittleEndianInputStream(in); + _bhi = new SimpleHeaderInput(_dataInput); } else { Biff8DecryptingStream bds = new Biff8DecryptingStream(in, initialOffset, key); _dataInput = bds; @@ -195,11 +199,9 @@ public final class RecordInputStream implements LittleEndianInput { private int readNextSid() { int nAvailable = _bhi.available(); if (nAvailable < EOFRecord.ENCODED_SIZE) { - /*if (nAvailable > 0) { - // some scrap left over? - // ex45582-22397.xls has one extra byte after the last record - // Excel reads that file OK - }*/ + // some scrap left over, if nAvailable > 0? + // ex45582-22397.xls has one extra byte after the last record + // Excel reads that file OK return INVALID_SID_VALUE; } int result = _bhi.readRecordSID(); @@ -305,14 +307,8 @@ public final class RecordInputStream implements LittleEndianInput { @Override public double readDouble() { - long valueLongBits = readLong(); - /*if (Double.isNaN(result)) { - // YK: Excel doesn't write NaN but instead converts the cell type into {@link CellType#ERROR}. - // HSSF prior to version 3.7 had a bug: it could write Double.NaN but could not read such a file back. - // This behavior was fixed in POI-3.7. - //throw new RuntimeException("Did not expect to read NaN"); // (Because Excel typically doesn't write NaN) - }*/ - return Double.longBitsToDouble(valueLongBits); + // YK: Excel doesn't write NaN but instead converts the cell type into {@link CellType#ERROR}. + return Double.longBitsToDouble(readLong()); } public void readPlain(byte[] buf, int off, int len) { @@ -329,7 +325,7 @@ public final class RecordInputStream implements LittleEndianInput { readFully(buf, off, len, false); } - protected void readFully(byte[] buf, int off, int len, boolean isPlain) { + private void readFully(byte[] buf, int off, int len, boolean isPlain) { int origLen = len; if (buf == null) { throw new NullPointerException(); diff --git a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java index a92c8dc590..c37ce006a0 100644 --- a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java +++ b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java @@ -40,6 +40,7 @@ import javax.imageio.ImageTypeSpecifier; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.MemoryCacheImageInputStream; +import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.util.IOUtils; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -48,11 +49,24 @@ import org.apache.poi.util.POILogger; * For now this class renders only images supported by the javax.imageio.ImageIO framework. **/ public class BitmapImageRenderer implements ImageRenderer { - private final static POILogger LOG = POILogFactory.getLogger(ImageRenderer.class); + private final static POILogger LOG = POILogFactory.getLogger(BitmapImageRenderer.class); protected BufferedImage img; @Override + public boolean canRender(String contentType) { + PictureType[] pts = { + PictureType.JPEG, PictureType.PNG, PictureType.BMP, PictureType.GIF + }; + for (PictureType pt : pts) { + if (pt.contentType.equalsIgnoreCase(contentType)) { + return true; + } + } + return false; + } + + @Override public void loadImage(InputStream data, String contentType) throws IOException { img = readImage(data, contentType); } diff --git a/src/java/org/apache/poi/sl/draw/DrawFactory.java b/src/java/org/apache/poi/sl/draw/DrawFactory.java index 98c41ed993..99c9942b67 100644 --- a/src/java/org/apache/poi/sl/draw/DrawFactory.java +++ b/src/java/org/apache/poi/sl/draw/DrawFactory.java @@ -22,8 +22,6 @@ import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.text.AttributedString; -import java.util.HashMap; -import java.util.Map; import org.apache.poi.sl.usermodel.Background; import org.apache.poi.sl.usermodel.ConnectorShape; @@ -40,18 +38,18 @@ import org.apache.poi.sl.usermodel.TableShape; import org.apache.poi.sl.usermodel.TextBox; import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextShape; -import org.apache.poi.util.JvmBugs; public class DrawFactory { - protected static final ThreadLocal<DrawFactory> defaultFactory = new ThreadLocal<>(); + private static final ThreadLocal<DrawFactory> defaultFactory = new ThreadLocal<>(); /** * Set a custom draw factory for the current thread. * This is a fallback, for operations where usercode can't set a graphics context. * Preferably use the rendering hint {@link Drawable#DRAW_FACTORY} to set the factory. * - * @param factory + * @param factory the custom factory */ + @SuppressWarnings("unused") public static void setDefaultFactory(DrawFactory factory) { defaultFactory.set(factory); } @@ -170,6 +168,7 @@ public class DrawFactory { return new DrawBackground(shape); } + @SuppressWarnings("WeakerAccess") public DrawTextFragment getTextFragment(TextLayout layout, AttributedString str) { return new DrawTextFragment(layout, str); } @@ -214,35 +213,6 @@ public class DrawFactory { /** - * Replace font families for Windows JVM 6, which contains a font rendering error. - * This is likely to be removed, when POI upgrades to JDK 7 - * - * @param graphics the graphics context which will contain the font mapping - */ - public void fixFonts(Graphics2D graphics) { - if (!JvmBugs.hasLineBreakMeasurerBug()) return; - @SuppressWarnings("unchecked") - Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP); - if (fontMap == null) { - fontMap = new HashMap<>(); - graphics.setRenderingHint(Drawable.FONT_MAP, fontMap); - } - - String fonts[][] = { - { "Calibri", "Lucida Sans" }, - { "Cambria", "Lucida Bright" }, - { "Times New Roman", "Lucida Bright" }, - { "serif", "Lucida Bright" } - }; - - for (String f[] : fonts) { - if (!fontMap.containsKey(f[0])) { - fontMap.put(f[0], f[1]); - } - } - } - - /** * Return a FontManager, either registered beforehand or a default implementation * * @param graphics the graphics context holding potentially a font manager diff --git a/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java index c439fc926f..a428943699 100644 --- a/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java +++ b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java @@ -22,6 +22,8 @@ package org.apache.poi.sl.draw; import java.awt.Font; import java.awt.Graphics2D; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import org.apache.poi.common.usermodel.fonts.FontInfo; import org.apache.poi.sl.draw.Drawable.DrawableHint; @@ -33,6 +35,13 @@ import org.apache.poi.sl.draw.Drawable.DrawableHint; */ public class DrawFontManagerDefault implements DrawFontManager { + protected final Set<String> knownSymbolFonts = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + + public DrawFontManagerDefault() { + knownSymbolFonts.add("Wingdings"); + knownSymbolFonts.add("Symbol"); + } + @Override public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) { return getFontWithFallback(graphics, Drawable.FONT_MAP, fontInfo); @@ -49,25 +58,35 @@ public class DrawFontManagerDefault implements DrawFontManager { public String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, String text) { // TODO: find a real charset mapping solution instead of hard coding for Wingdings - String attStr = text; - if (fontInfo != null && "Wingdings".equalsIgnoreCase(fontInfo.getTypeface())) { - // wingdings doesn't contain high-surrogates, so chars are ok - boolean changed = false; - char chrs[] = attStr.toCharArray(); - for (int i=0; i<chrs.length; i++) { - // only change valid chars - if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) || - (0xa0 <= chrs[i] && chrs[i] <= 0xff)) { - chrs[i] |= 0xf000; - changed = true; - } - } + return (fontInfo != null && knownSymbolFonts.contains(fontInfo.getTypeface())) + ? mapSymbolChars(text) + : text; + } - if (changed) { - attStr = new String(chrs); + /** + * Symbol fonts like "Wingdings" or "Symbol" have glyphs mapped to a Unicode private use range via the Java font loader, + * although a system font viewer might show you the glyphs in the ASCII range. + * This helper function maps the chars of the text string to the corresponding private use range chars. + * + * @param text the input string, typically consists of ASCII chars + * @return the mapped string, typically consists of chars in the range of 0xf000 to 0xf0ff + * + * @since POI 4.0.0 + */ + public static String mapSymbolChars(String text) { + // wingdings doesn't contain high-surrogates, so chars are ok + boolean changed = false; + char chrs[] = text.toCharArray(); + for (int i=0; i<chrs.length; i++) { + // only change valid chars + if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) || + (0xa0 <= chrs[i] && chrs[i] <= 0xff)) { + chrs[i] |= 0xf000; + changed = true; } } - return attStr; + + return changed ? new String(chrs) : text; } @Override diff --git a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java index fcca6d07a7..3ccbc9f219 100644 --- a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java @@ -22,19 +22,22 @@ import java.awt.Graphics2D; import java.awt.Insets; import java.awt.geom.Rectangle2D; import java.io.IOException; +import java.util.ServiceLoader; import org.apache.poi.sl.usermodel.PictureData; -import org.apache.poi.sl.usermodel.PictureData.PictureType; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.RectAlign; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; public class DrawPictureShape extends DrawSimpleShape { private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class); - private static final String WMF_IMAGE_RENDERER = "org.apache.poi.hwmf.draw.HwmfSLImageRenderer"; - + private static final String[] KNOWN_RENDERER = { + "org.apache.poi.hwmf.draw.HwmfImageRenderer", + "org.apache.poi.hemf.draw.HemfImageRenderer" + }; + public DrawPictureShape(PictureShape<?,?> shape) { super(shape); } @@ -59,29 +62,47 @@ public class DrawPictureShape extends DrawSimpleShape { /** * Returns an ImageRenderer for the PictureData * - * @param graphics + * @param graphics the graphics context * @return the image renderer */ + @SuppressWarnings({"WeakerAccess", "unchecked"}) public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) { - ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER); - if (renderer != null) { + final ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER); + if (renderer != null && renderer.canRender(contentType)) { return renderer; } - - if (PictureType.WMF.contentType.equals(contentType)) { + + // first try with our default image renderer + final BitmapImageRenderer bir = new BitmapImageRenderer(); + if (bir.canRender(contentType)) { + return bir; + } + + // then iterate through the scratchpad renderers + // + // this could be nicely implemented via a j.u.ServiceLoader, but OSGi makes things complicated ... + // https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html + // ... therefore falling back to classloading attempts + ClassLoader cl = ImageRenderer.class.getClassLoader(); + for (String kr : KNOWN_RENDERER) { + final ImageRenderer ir; try { - @SuppressWarnings("unchecked") - Class<? extends ImageRenderer> irc = (Class<? extends ImageRenderer>) - DrawPictureShape.class.getClassLoader().loadClass(WMF_IMAGE_RENDERER); - return irc.newInstance(); - } catch (Exception e) { - // WMF image renderer is not on the classpath, continuing with BitmapRenderer - // although this doesn't make much sense ... - LOG.log(POILogger.ERROR, "WMF image renderer is not on the classpath - include poi-scratchpad jar!", e); + ir = ((Class<? extends ImageRenderer>)cl.loadClass(kr)).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + // scratchpad was not on the path, ignore and continue + LOG.log(POILogger.INFO, "Known image renderer '"+kr+" not found/loaded - include poi-scratchpad jar!", e); + continue; + } + if (ir.canRender(contentType)) { + return ir; } } - - return new BitmapImageRenderer(); + + LOG.log(POILogger.WARN, "No suiteable image renderer found for content-type '"+ + contentType+"' - include poi-scratchpad jar!"); + + // falling back to BitmapImageRenderer, at least it gracefully handles invalid images + return bir; } @Override diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java index 938d46230a..1ab4af3a1e 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -254,7 +254,6 @@ public class DrawTextParagraph implements Drawable { lines.clear(); DrawFactory fact = DrawFactory.getInstance(graphics); - fact.fixFonts(graphics); StringBuilder text = new StringBuilder(); AttributedString at = getAttributedString(graphics, text); boolean emptyParagraph = text.toString().trim().isEmpty(); @@ -635,13 +634,6 @@ public class DrawTextParagraph implements Drawable { * <li>determine the font group - a text run can have different font groups. Depending on the chars, * the correct font group needs to be used * - * @param graphics - * @param dfm - * @param attList - * @param beginIndex - * @param run - * @param runText - * * @see <a href="https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/">Office Open XML Themes, Schemes, and Fonts</a> */ private void processGlyphs(Graphics2D graphics, DrawFontManager dfm, List<AttributedStringData> attList, final int beginIndex, TextRun run, String runText) { diff --git a/src/java/org/apache/poi/sl/draw/DrawTextShape.java b/src/java/org/apache/poi/sl/draw/DrawTextShape.java index 413ab218c9..c4dd65bb75 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextShape.java @@ -40,8 +40,6 @@ public class DrawTextShape extends DrawSimpleShape { @Override public void drawContent(Graphics2D graphics) { - DrawFactory.getInstance(graphics).fixFonts(graphics); - TextShape<?,?> s = getShape(); Rectangle2D anchor = DrawShape.getAnchor(graphics, s); @@ -219,10 +217,9 @@ public class DrawTextShape extends DrawSimpleShape { graphics.addRenderingHints(oldGraphics.getRenderingHints()); graphics.setTransform(oldGraphics.getTransform()); } - DrawFactory.getInstance(graphics).fixFonts(graphics); return drawParagraphs(graphics, 0, 0); } - + @Override protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() { return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape; diff --git a/src/java/org/apache/poi/sl/draw/ImageRenderer.java b/src/java/org/apache/poi/sl/draw/ImageRenderer.java index 7ecc96a967..b2355b3012 100644 --- a/src/java/org/apache/poi/sl/draw/ImageRenderer.java +++ b/src/java/org/apache/poi/sl/draw/ImageRenderer.java @@ -76,6 +76,13 @@ import java.io.InputStream; */ public interface ImageRenderer { /** + * Determines if this image renderer implementation supports the given contentType + * @param contentType the image content type + * @return if the content type is supported + */ + boolean canRender(String contentType); + + /** * Load and buffer the image * * @param data the raw image stream diff --git a/src/java/org/apache/poi/util/Dimension2DDouble.java b/src/java/org/apache/poi/util/Dimension2DDouble.java new file mode 100644 index 0000000000..d08906433c --- /dev/null +++ b/src/java/org/apache/poi/util/Dimension2DDouble.java @@ -0,0 +1,73 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.util; + +import java.awt.geom.Dimension2D; + +public class Dimension2DDouble extends Dimension2D { + + double width; + double height; + + public Dimension2DDouble() { + width = 0d; + height = 0d; + } + + public Dimension2DDouble(double width, double height) { + this.width = width; + this.height = height; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public void setSize(double width, double height) { + this.width = width; + this.height = height; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Dimension2DDouble) { + Dimension2DDouble other = (Dimension2DDouble) obj; + return width == other.width && height == other.height; + } + + return false; + } + + @Override + public int hashCode() { + double sum = width + height; + return (int) Math.ceil(sum * (sum + 1) / 2 + width); + } + + @Override + public String toString() { + return "Dimension2DDouble[" + width + ", " + height + "]"; + } +} diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java index 009510ffc6..3dd4cb0d57 100644 --- a/src/java/org/apache/poi/util/IOUtils.java +++ b/src/java/org/apache/poi/util/IOUtils.java @@ -50,6 +50,7 @@ public final class IOUtils { * @param maxOverride The number of bytes that should be possible to be allocated in one step. * @since 4.0.0 */ + @SuppressWarnings("unused") public static void setByteArrayMaxOverride(int maxOverride) { BYTE_ARRAY_MAX_OVERRIDE = maxOverride; } @@ -395,13 +396,35 @@ public final class IOUtils { * @throws IOException If copying the data fails. */ public static long copy(InputStream inp, OutputStream out) throws IOException { + return copy(inp, out, -1); + } + + /** + * Copies all the data from the given InputStream to the OutputStream. It + * leaves both streams open, so you will still need to close them once done. + * + * @param inp The {@link InputStream} which provides the data + * @param out The {@link OutputStream} to write the data to + * @param limit limit the copied bytes - use {@code -1} for no limit + * @return the amount of bytes copied + * + * @throws IOException If copying the data fails. + */ + public static long copy(InputStream inp, OutputStream out, long limit) throws IOException { final byte[] buff = new byte[4096]; long totalCount = 0; - for (int count; (count = inp.read(buff)) != -1; totalCount += count) { - if (count > 0) { - out.write(buff, 0, count); + int readBytes = -1; + do { + int todoBytes = (int)((limit < 0) ? buff.length : Math.min(limit-totalCount, buff.length)); + if (todoBytes > 0) { + readBytes = inp.read(buff, 0, todoBytes); + if (readBytes > 0) { + out.write(buff, 0, readBytes); + totalCount += readBytes; + } } - } + } while (readBytes >= 0 && (limit == -1 || totalCount < limit)); + return totalCount; } diff --git a/src/java/org/apache/poi/util/LittleEndianInputStream.java b/src/java/org/apache/poi/util/LittleEndianInputStream.java index 886720f3f1..6199c4dd12 100644 --- a/src/java/org/apache/poi/util/LittleEndianInputStream.java +++ b/src/java/org/apache/poi/util/LittleEndianInputStream.java @@ -17,6 +17,7 @@ package org.apache.poi.util; +import java.io.BufferedInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; @@ -29,12 +30,16 @@ import java.io.InputStream; */ public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput { + private static final int BUFFERED_SIZE = 8096; + private static final int EOF = -1; + private int readIndex = 0; + private int markIndex = -1; public LittleEndianInputStream(InputStream is) { - super(is); + super(is.markSupported() ? is : new BufferedInputStream(is, BUFFERED_SIZE)); } - + @Override @SuppressForbidden("just delegating") public int available() { @@ -60,7 +65,18 @@ public class LittleEndianInputStream extends FilterInputStream implements Little } return LittleEndian.getUByte(buf); } - + + /** + * get a float value, reads it in little endian format + * then converts the resulting revolting IEEE 754 (curse them) floating + * point number to a happy java float + * + * @return the float (32-bit) value + */ + public float readFloat() { + return Float.intBitsToFloat( readInt() ); + } + @Override public double readDouble() { return Double.longBitsToDouble(readLong()); @@ -137,14 +153,42 @@ public class LittleEndianInputStream extends FilterInputStream implements Little } } - //Makes repeated calls to super.read() until length is read or EOF is reached + @Override + public int read(byte[] b, int off, int len) throws IOException { + int readBytes = super.read(b, off, len); + readIndex += readBytes; + return readBytes; + } + + @Override + public synchronized void mark(int readlimit) { + super.mark(readlimit); + markIndex = readIndex; + } + + @Override + public synchronized void reset() throws IOException { + super.reset(); + if (markIndex > -1) { + readIndex = markIndex; + markIndex = -1; + } + } + + public int getReadIndex() { + return readIndex; + } + + + + //Makes repeated calls to super.read() until length is read or EOF is reached private int _read(byte[] buffer, int offset, int length) throws IOException { //lifted directly from org.apache.commons.io.IOUtils 2.4 int remaining = length; while (remaining > 0) { int location = length - remaining; int count = read(buffer, offset + location, remaining); - if (EOF == count) { // EOF + if (EOF == count) { break; } remaining -= count; @@ -157,4 +201,9 @@ public class LittleEndianInputStream extends FilterInputStream implements Little public void readPlain(byte[] buf, int off, int len) { readFully(buf, off, len); } + + + public void skipFully(int len) throws IOException { + IOUtils.skipFully(this, len); + } } |