diff --git a/imageio/imageio-batik/src/main/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpi.java b/imageio/imageio-batik/src/main/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpi.java index a9a4c820..a69602fa 100755 --- a/imageio/imageio-batik/src/main/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpi.java +++ b/imageio/imageio-batik/src/main/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpi.java @@ -36,9 +36,11 @@ import com.twelvemonkeys.lang.SystemUtil; import javax.imageio.ImageReader; import javax.imageio.spi.ServiceRegistry; import javax.imageio.stream.ImageInputStream; +import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.util.Locale; +import java.util.function.Predicate; import static com.twelvemonkeys.imageio.util.IIOUtil.deregisterProvider; @@ -134,10 +136,40 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase { if (buffer[0] == 's' && buffer[1] == 'v' && buffer[2] == 'g' && (Character.isWhitespace((char) buffer[3]) || buffer[3] == ':')) { // It's SVG, identified by root tag - // TODO: Support svg with prefix + recognize namespace (http://www.w3.org/2000/svg)! return true; } + // Read the full tag name (may contain a prefix of any length) + ByteArrayOutputStream nameBuf = new ByteArrayOutputStream(); + + // We already have 4 bytes in 'buffer' (from input.readFully(buffer)) + int consumedFromBuffer = 0; + for (; consumedFromBuffer < buffer.length; consumedFromBuffer++) { + byte bb = buffer[consumedFromBuffer]; + if (bb == '>' || Character.isWhitespace((char) bb) || bb == '/') { + break; + } + nameBuf.write(bb); + } + + // If tag name not terminated yet, keep reading bytes (within limit) + final int MAX_TAG_NAME = 256; + final boolean incompleteTagName = consumedFromBuffer == buffer.length; + readBuffer(input, nameBuf, x -> incompleteTagName && x.size() < MAX_TAG_NAME, + bb -> bb == '>' || Character.isWhitespace(bb) || bb == '/'); + + if (nameBuf.toString("US-ASCII").toLowerCase(Locale.ENGLISH).endsWith(":svg")) { + // Scan the rest of the tag attributes until '>' to find the SVG namespace URI + ByteArrayOutputStream attrBuf = new ByteArrayOutputStream(); + final int MAX_ATTR_SCAN = 1024; // safe upper bound to keep it fast + readBuffer(input, attrBuf, x -> x.size() < MAX_ATTR_SCAN, bb -> bb == '>'); + + // If the tag contains the SVG namespace, it's SVG. + if (attrBuf.toString("US-ASCII").contains("http://www.w3.org/2000/svg")) { + return true; + } + } + // If the tag is not "svg", this isn't SVG return false; } @@ -157,6 +189,21 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase { } } + private static void readBuffer(final ImageInputStream input, final ByteArrayOutputStream buffer, + final Predicate loopCondition, Predicate breakCondition) throws IOException { + while (loopCondition.test(buffer)) { + int r = input.read(); + if (r == -1) { + throw new EOFException(); + } + byte bb = (byte) r; + if (breakCondition.test(bb)) { + break; + } + buffer.write(bb); + } + } + public ImageReader createReaderInstance(final Object extension) throws IOException { return new SVGImageReader(this); } diff --git a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpiTest.java b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpiTest.java index 5aaf83aa..e2224647 100644 --- a/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpiTest.java +++ b/imageio/imageio-batik/src/test/java/com/twelvemonkeys/imageio/plugins/svg/SVGImageReaderSpiTest.java @@ -56,7 +56,7 @@ public class SVGImageReaderSpiTest { "/svg/Android_robot.svg", // Minimal, no xml dec, no namespace "/svg/batikLogo.svg", // xml dec, comments, namespace "/svg/blue-square.svg", // xml dec, namespace - "/svg/red-square.svg", + "/svg/red-square.svg", // prefixed namespace }; private static final String[] INVALID_INPUTS = { diff --git a/imageio/imageio-batik/src/test/resources/svg/red-square.svg b/imageio/imageio-batik/src/test/resources/svg/red-square.svg index 2ae064db..36b2260a 100644 --- a/imageio/imageio-batik/src/test/resources/svg/red-square.svg +++ b/imageio/imageio-batik/src/test/resources/svg/red-square.svg @@ -1,7 +1,7 @@ - - - + + - - + +