static public Reader scanForXMPPacket(final Object pInput) throws IOException {
        ImageInputStream stream = pInput instanceof ImageInputStream ? (ImageInputStream) pInput : ImageIO.createImageInputStream(pInput);

        // TODO: Consider if BufferedIIS is a good idea
        if (!(stream instanceof BufferedImageInputStream)) {
            stream = new BufferedImageInputStream(stream);
        }

        // TODO: Might be more than one XMP block per file (it's possible to re-start for now)..
        long pos;
        pos = scanForSequence(stream, XMP_PACKET_BEGIN);

        if (pos >= 0) {
            // Skip ' OR " (plus possible nulls for 16/32 bit)
            byte quote = stream.readByte();

            if (quote == '\'' || quote == '"') {
                Charset cs = null;

                // Read BOM
                byte[] bom = new byte[4];
                stream.readFully(bom);

                // NOTE: Empty string should be treated as UTF-8 for backwards compatibility
                if (bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF && bom[3] == quote ||
                        bom[0] == quote) {
                    // UTF-8
                    cs = Charset.forName("UTF-8");
                }
                else if (bom[0] == (byte) 0xFE && bom[1] == (byte) 0xFF && bom[2] == 0x00 && bom[3] == quote) {
                    // UTF-16 BIG endian
                    cs = Charset.forName("UTF-16BE");
                }
                else if (bom[0] == 0x00 && bom[1] == (byte) 0xFF && bom[2] == (byte) 0xFE && bom[3] == quote) {
                    stream.skipBytes(1); // Alignment

                    // UTF-16 little endian
                    cs = Charset.forName("UTF-16LE");
                }
                else if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == (byte) 0xFE && bom[3] == (byte) 0xFF) {
                    // NOTE: 32-bit character set not supported by default
                    // UTF 32 BIG endian
                    cs = Charset.forName("UTF-32BE");
                }
                else if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == 0x00 && bom[3] == (byte) 0xFF && stream.read() == 0xFE) {
                    stream.skipBytes(2); // Alignment
                    // NOTE: 32-bit character set not supported by default
                    // UTF 32 little endian
                    cs = Charset.forName("UTF-32LE");
                }

                if (cs != null) {
                    // Read all bytes until <?xpacket end= up-front or filter stream
                    stream.mark();
                    long end = scanForSequence(stream, XMP_PACKET_END);
                    stream.reset();

                    long length = end - stream.getStreamPosition();
                    Reader reader = new InputStreamReader(IIOUtil.createStreamAdapter(stream, length), cs);

                    // Skip until ?>
                    while (reader.read() != '>') {
                    }

                    // Return reader?
                    // How to decide between w or r?!
                    return reader;
                }
            }
        }

        return null;
    }
static public Reader scanForXMPPacket ( final Object pInput ) throws IOException { ImageInputStream stream = pInput instanceof ImageInputStream ? ( ImageInputStream ) pInput : ImageIO . createImageInputStream ( pInput ) ; if ( ! ( stream instanceof BufferedImageInputStream ) ) { stream = new BufferedImageInputStream ( stream ) ; } long pos ; pos = scanForSequence ( stream , XMP_PACKET_BEGIN ) ; if ( pos >= 0 ) { byte quote = stream . readByte ( ) ; if ( quote == '\'' || quote == '"' ) { Charset cs = null ; byte [ ] bom = new byte [ 4 ] ; stream . readFully ( bom ) ; if ( bom [ 0 ] == ( byte ) 0xEF && bom [ 1 ] == ( byte ) 0xBB && bom [ 2 ] == ( byte ) 0xBF && bom [ 3 ] == quote || bom [ 0 ] == quote ) { cs = Charset . forName ( "UTF-8" ) ; } else if ( bom [ 0 ] == ( byte ) 0xFE && bom [ 1 ] == ( byte ) 0xFF && bom [ 2 ] == 0x00 && bom [ 3 ] == quote ) { cs = Charset . forName ( "UTF-16BE" ) ; } else if ( bom [ 0 ] == 0x00 && bom [ 1 ] == ( byte ) 0xFF && bom [ 2 ] == ( byte ) 0xFE && bom [ 3 ] == quote ) { stream . skipBytes ( 1 ) ; cs = Charset . forName ( "UTF-16LE" ) ; } else if ( bom [ 0 ] == 0x00 && bom [ 1 ] == 0x00 && bom [ 2 ] == ( byte ) 0xFE && bom [ 3 ] == ( byte ) 0xFF ) { cs = Charset . forName ( "UTF-32BE" ) ; } else if ( bom [ 0 ] == 0x00 && bom [ 1 ] == 0x00 && bom [ 2 ] == 0x00 && bom [ 3 ] == ( byte ) 0xFF && stream . read ( ) == 0xFE ) { stream . skipBytes ( 2 ) ; cs = Charset . forName ( "UTF-32LE" ) ; } if ( cs != null ) { stream . mark ( ) ; long end = scanForSequence ( stream , XMP_PACKET_END ) ; stream . reset ( ) ; long length = end - stream . getStreamPosition ( ) ; Reader reader = new InputStreamReader ( IIOUtil . createStreamAdapter ( stream , length ) , cs ) ; while ( reader . read ( ) != '>' ) { } return reader ; } } } return null ; }
Scans the given input for an XML metadata packet.
The scanning process involves reading every byte in the file, while searching for an XMP packet.
This process is very inefficient, compared to reading a known file format.
<p/>
<em>NOTE: The XMP Specification says this method of reading an XMP packet
should be considered a last resort.</em><br/>
This is because files may contain multiple XMP packets, some which may be related to embedded resources,
some which may be obsolete (or even incomplete).

@param pInput the input to scan. The input may be an {@link javax.imageio.stream.ImageInputStream} or
any object that can be passed to {@link ImageIO#createImageInputStream(Object)}.
Typically this may be a {@link File}, {@link InputStream} or {@link java.io.RandomAccessFile}.

@return a character Reader

@throws java.nio.charset.UnsupportedCharsetException if the encoding specified within the BOM is not supported
by the JRE.
@throws IOException if an I/O exception occurs reading from {@code pInput}.
@see ImageIO#createImageInputStream(Object)