alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (WDataTransferer.java)

This example Java source code file (WDataTransferer.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, body, cf_jfif, cf_png, clipboard, dataflavor, datatransfer, drag, ehtmlreadmode, endfragment, html, image, ioexception, long, padded_width, startfragment, string, util, version, wdatatransferer

The WDataTransferer.java Java example source code

/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.awt.windows;

import java.awt.Image;
import java.awt.Graphics2D;
import java.awt.Transparency;

import java.awt.color.ColorSpace;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorTable;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;

import java.awt.geom.AffineTransform;

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.File;

import java.net.URL;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;

import sun.awt.Mutex;
import sun.awt.datatransfer.DataTransferer;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;

import sun.awt.image.ImageRepresentation;
import sun.awt.image.ToolkitImage;

import java.util.ArrayList;

import java.io.ByteArrayOutputStream;

/**
 * Platform-specific support for the data transfer subsystem.
 *
 * @author David Mendenhall
 * @author Danila Sinopalnikov
 *
 * @since 1.3.1
 */
public class WDataTransferer extends DataTransferer {
    private static final String[] predefinedClipboardNames = {
            "",
            "TEXT",
            "BITMAP",
            "METAFILEPICT",
            "SYLK",
            "DIF",
            "TIFF",
            "OEM TEXT",
            "DIB",
            "PALETTE",
            "PENDATA",
            "RIFF",
            "WAVE",
            "UNICODE TEXT",
            "ENHMETAFILE",
            "HDROP",
            "LOCALE",
            "DIBV5"
    };

    private static final Map <String, Long> predefinedClipboardNameMap;
    static {
        Map <String,Long> tempMap =
                new HashMap <> (predefinedClipboardNames.length, 1.0f);
        for (int i = 1; i < predefinedClipboardNames.length; i++) {
            tempMap.put(predefinedClipboardNames[i], Long.valueOf(i));
        }
        predefinedClipboardNameMap =
                Collections.synchronizedMap(tempMap);
    }

    /**
     * from winuser.h
     */
    public static final int CF_TEXT = 1;
    public static final int CF_METAFILEPICT = 3;
    public static final int CF_DIB = 8;
    public static final int CF_ENHMETAFILE = 14;
    public static final int CF_HDROP = 15;
    public static final int CF_LOCALE = 16;

    public static final long CF_HTML = registerClipboardFormat("HTML Format");
    public static final long CFSTR_INETURL = registerClipboardFormat("UniformResourceLocator");
    public static final long CF_PNG = registerClipboardFormat("PNG");
    public static final long CF_JFIF = registerClipboardFormat("JFIF");

    public static final long CF_FILEGROUPDESCRIPTORW = registerClipboardFormat("FileGroupDescriptorW");
    public static final long CF_FILEGROUPDESCRIPTORA = registerClipboardFormat("FileGroupDescriptor");
    //CF_FILECONTENTS supported as mandatory associated clipboard

    private static final Long L_CF_LOCALE =
            predefinedClipboardNameMap.get(predefinedClipboardNames[CF_LOCALE]);

    private static final DirectColorModel directColorModel =
            new DirectColorModel(24,
                    0x00FF0000,  /* red mask   */
                    0x0000FF00,  /* green mask */
                    0x000000FF); /* blue mask  */

    private static final int[] bandmasks = new int[] {
            directColorModel.getRedMask(),
            directColorModel.getGreenMask(),
            directColorModel.getBlueMask() };

    /**
     * Singleton constructor
     */
    private WDataTransferer() {
    }

    private static WDataTransferer transferer;

    public static WDataTransferer getInstanceImpl() {
        if (transferer == null) {
            synchronized (WDataTransferer.class) {
                if (transferer == null) {
                    transferer = new WDataTransferer();
                }
            }
        }
        return transferer;
    }

    public SortedMap <Long, DataFlavor> getFormatsForFlavors(
            DataFlavor[] flavors, FlavorTable map)
    {
        SortedMap <Long, DataFlavor> retval =
                super.getFormatsForFlavors(flavors, map);

        // The Win32 native code does not support exporting LOCALE data, nor
        // should it.
        retval.remove(L_CF_LOCALE);

        return retval;
    }

    public String getDefaultUnicodeEncoding() {
        return "utf-16le";
    }

    public byte[] translateTransferable(Transferable contents,
                                        DataFlavor flavor,
                                        long format) throws IOException
    {
        byte[] bytes = null;
        if (format == CF_HTML) {
            if (contents.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor)) {
                // if a user provides data represented by
                // DataFlavor.selectionHtmlFlavor format, we use this
                // type to store the data in the native clipboard
                bytes = super.translateTransferable(contents,
                        DataFlavor.selectionHtmlFlavor,
                        format);
            } else if (contents.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) {
                // if we cannot get data represented by the
                // DataFlavor.selectionHtmlFlavor format
                // but the DataFlavor.allHtmlFlavor format is avialable
                // we belive that the user knows how to represent
                // the data and how to mark up selection in a
                // system specific manner. Therefor, we use this data
                bytes = super.translateTransferable(contents,
                        DataFlavor.allHtmlFlavor,
                        format);
            } else {
                // handle other html flavor types, including custom and
                // fragment ones
                bytes = HTMLCodec.convertToHTMLFormat(super.translateTransferable(contents, flavor, format));
            }
        } else {
            // we handle non-html types basing on  their
            // flavors
            bytes = super.translateTransferable(contents, flavor, format);
        }
        return bytes;
    }

    // The stream is closed as a closable object
    public Object translateStream(InputStream str,
                                 DataFlavor flavor, long format,
                                 Transferable localeTransferable)
        throws IOException
    {
        if (format == CF_HTML && flavor.isFlavorTextType()) {
            str = new HTMLCodec(str,
                                 EHTMLReadMode.getEHTMLReadMode(flavor));

        }
        return super.translateStream(str, flavor, format,
                                        localeTransferable);

    }

    public Object translateBytes(byte[] bytes, DataFlavor flavor, long format,
        Transferable localeTransferable) throws IOException
    {


        if (format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW) {
            if (bytes == null || !DataFlavor.javaFileListFlavor.equals(flavor)) {
                throw new IOException("data translation failed");
            }
            String st = new String(bytes, 0, bytes.length, "UTF-16LE");
            String[] filenames = st.split("\0");
            if( 0 == filenames.length ){
                return null;
            }

            // Convert the strings to File objects
            File[] files = new File[filenames.length];
            for (int i = 0; i < filenames.length; ++i) {
                files[i] = new File(filenames[i]);
                //They are temp-files from memory Stream, so they have to be removed on exit
                files[i].deleteOnExit();
            }
            // Turn the list of Files into a List and return
            return Arrays.asList(files);
        }

        if (format == CFSTR_INETURL &&
                URL.class.equals(flavor.getRepresentationClass()))
        {
            String charset = getDefaultTextCharset();
            if (localeTransferable != null && localeTransferable.
                                                                    isDataFlavorSupported(javaTextEncodingFlavor))
            {
                try {
                    charset = new String((byte[])localeTransferable.
                        getTransferData(javaTextEncodingFlavor), "UTF-8");
                } catch (UnsupportedFlavorException cannotHappen) {
                }
            }
            return new URL(new String(bytes, charset));
        }

        return super.translateBytes(bytes , flavor, format,
                                        localeTransferable);

    }

    public boolean isLocaleDependentTextFormat(long format) {
        return format == CF_TEXT || format == CFSTR_INETURL;
    }

    public boolean isFileFormat(long format) {
        return format == CF_HDROP || format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW;
    }

    protected Long getFormatForNativeAsLong(String str) {
        Long format = predefinedClipboardNameMap.get(str);
        if (format == null) {
            format = Long.valueOf(registerClipboardFormat(str));
        }
        return format;
    }

    protected String getNativeForFormat(long format) {
        return (format < predefinedClipboardNames.length)
                ? predefinedClipboardNames[(int)format]
                : getClipboardFormatName(format);
    }

    private final ToolkitThreadBlockedHandler handler =
            new WToolkitThreadBlockedHandler();

    public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
        return handler;
    }

    /**
     * Calls the Win32 RegisterClipboardFormat function to register
     * a non-standard format.
     */
    private static native long registerClipboardFormat(String str);

    /**
     * Calls the Win32 GetClipboardFormatName function which is
     * the reverse operation of RegisterClipboardFormat.
     */
    private static native String getClipboardFormatName(long format);

    public boolean isImageFormat(long format) {
        return format == CF_DIB || format == CF_ENHMETAFILE ||
                format == CF_METAFILEPICT || format == CF_PNG ||
                format == CF_JFIF;
    }

    protected byte[] imageToPlatformBytes(Image image, long format)
            throws IOException {
        String mimeType = null;
        if (format == CF_PNG) {
            mimeType = "image/png";
        } else if (format == CF_JFIF) {
            mimeType = "image/jpeg";
        }
        if (mimeType != null) {
            return imageToStandardBytes(image, mimeType);
        }

        int width = 0;
        int height = 0;

        if (image instanceof ToolkitImage) {
            ImageRepresentation ir = ((ToolkitImage)image).getImageRep();
            ir.reconstruct(ImageObserver.ALLBITS);
            width = ir.getWidth();
            height = ir.getHeight();
        } else {
            width = image.getWidth(null);
            height = image.getHeight(null);
        }

        // Fix for 4919639.
        // Some Windows native applications (e.g. clipbrd.exe) do not handle
        // 32-bpp DIBs correctly.
        // As a workaround we switched to 24-bpp DIBs.
        // MSDN prescribes that the bitmap array for a 24-bpp should consist of
        // 3-byte triplets representing blue, green and red components of a
        // pixel respectively. Additionally each scan line must be padded with
        // zeroes to end on a LONG data-type boundary. LONG is always 32-bit.
        // We render the given Image to a BufferedImage of type TYPE_3BYTE_BGR
        // with non-default scanline stride and pass the resulting data buffer
        // to the native code to fill the BITMAPINFO structure.
        int mod = (width * 3) % 4;
        int pad = mod > 0 ? 4 - mod : 0;

        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
        int[] nBits = {8, 8, 8};
        int[] bOffs = {2, 1, 0};
        ColorModel colorModel =
                new ComponentColorModel(cs, nBits, false, false,
                        Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        WritableRaster raster =
                Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
                        width * 3 + pad, 3, bOffs, null);

        BufferedImage bimage = new BufferedImage(colorModel, raster, false, null);

        // Some Windows native applications (e.g. clipbrd.exe) do not understand
        // top-down DIBs.
        // So we flip the image vertically and create a bottom-up DIB.
        AffineTransform imageFlipTransform =
                new AffineTransform(1, 0, 0, -1, 0, height);

        Graphics2D g2d = bimage.createGraphics();

        try {
            g2d.drawImage(image, imageFlipTransform, null);
        } finally {
            g2d.dispose();
        }

        DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();

        byte[] imageData = buffer.getData();
        return imageDataToPlatformImageBytes(imageData, width, height, format);
    }

    private static final byte [] UNICODE_NULL_TERMINATOR =  new byte [] {0,0};

    protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
            throws IOException
    {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        if(fileList.isEmpty()) {
            //store empty unicode string (null terminator)
            bos.write(UNICODE_NULL_TERMINATOR);
        } else {
            for (int i = 0; i < fileList.size(); i++) {
                byte[] bytes = fileList.get(i).getBytes(getDefaultUnicodeEncoding());
                //store unicode string with null terminator
                bos.write(bytes, 0, bytes.length);
                bos.write(UNICODE_NULL_TERMINATOR);
            }
        }

        // According to MSDN the byte array have to be double NULL-terminated.
        // The array contains Unicode characters, so each NULL-terminator is
        // a pair of bytes

        bos.write(UNICODE_NULL_TERMINATOR);
        return bos;
    }

    /**
     * Returns a byte array which contains data special for the given format
     * and for the given image data.
     */
    private native byte[] imageDataToPlatformImageBytes(byte[] imageData,
                                                        int width, int height,
                                                        long format);

    /**
     * Translates either a byte array or an input stream which contain
     * platform-specific image data in the given format into an Image.
     */
    protected Image platformImageBytesToImage(byte[] bytes, long format)
            throws IOException {
        String mimeType = null;
        if (format == CF_PNG) {
            mimeType = "image/png";
        } else if (format == CF_JFIF) {
            mimeType = "image/jpeg";
        }
        if (mimeType != null) {
            return standardImageBytesToImage(bytes, mimeType);
        }

        int[] imageData = platformImageBytesToImageData(bytes, format);
        if (imageData == null) {
            throw new IOException("data translation failed");
        }

        int len = imageData.length - 2;
        int width = imageData[len];
        int height = imageData[len + 1];

        DataBufferInt buffer = new DataBufferInt(imageData, len);
        WritableRaster raster = Raster.createPackedRaster(buffer, width,
                height, width,
                bandmasks, null);

        return new BufferedImage(directColorModel, raster, false, null);
    }

    /**
     * Translates a byte array which contains platform-specific image data in
     * the given format into an integer array which contains pixel values in
     * ARGB format. The two last elements in the array specify width and
     * height of the image respectively.
     */
    private native int[] platformImageBytesToImageData(byte[] bytes,
                                                       long format)
            throws IOException;

    protected native String[] dragQueryFile(byte[] bytes);
}

final class WToolkitThreadBlockedHandler extends Mutex
        implements ToolkitThreadBlockedHandler {

    public void enter() {
        if (!isOwned()) {
            throw new IllegalMonitorStateException();
        }
        unlock();
        startSecondaryEventLoop();
        lock();
    }

    public void exit() {
        if (!isOwned()) {
            throw new IllegalMonitorStateException();
        }
        WToolkit.quitSecondaryEventLoop();
    }

    private native void startSecondaryEventLoop();
}

enum EHTMLReadMode {
    HTML_READ_ALL,
    HTML_READ_FRAGMENT,
    HTML_READ_SELECTION;

    public static EHTMLReadMode getEHTMLReadMode (DataFlavor df) {

        EHTMLReadMode mode = HTML_READ_SELECTION;

        String parameter = df.getParameter("document");

        if ("all".equals(parameter)) {
            mode = HTML_READ_ALL;
        } else if ("fragment".equals(parameter)) {
            mode = HTML_READ_FRAGMENT;
        }

        return mode;
    }
}

/**
 * on decode: This stream takes an InputStream which provides data in CF_HTML format,
 * strips off the description and context to extract the original HTML data.
 *
 * on encode: static convertToHTMLFormat is responsible for HTML clipboard header creation
 */
class HTMLCodec extends InputStream {
    //static section
    public static final String ENCODING = "UTF-8";

    public static final String VERSION = "Version:";
    public static final String START_HTML = "StartHTML:";
    public static final String END_HTML = "EndHTML:";
    public static final String START_FRAGMENT = "StartFragment:";
    public static final String END_FRAGMENT = "EndFragment:";
    public static final String START_SELECTION = "StartSelection:"; //optional
    public static final String END_SELECTION = "EndSelection:"; //optional

    public static final String START_FRAGMENT_CMT = "<!--StartFragment-->";
    public static final String END_FRAGMENT_CMT = "<!--EndFragment-->";
    public static final String SOURCE_URL = "SourceURL:";
    public static final String DEF_SOURCE_URL = "about:blank";

    public static final String EOLN = "\r\n";

    private static final String VERSION_NUM = "1.0";
    private static final int PADDED_WIDTH = 10;

    private static String toPaddedString(int n, int width) {
        String string = "" + n;
        int len = string.length();
        if (n >= 0 && len < width) {
            char[] array = new char[width - len];
            Arrays.fill(array, '0');
            StringBuffer buffer = new StringBuffer(width);
            buffer.append(array);
            buffer.append(string);
            string = buffer.toString();
        }
        return string;
    }

    /**
     * convertToHTMLFormat adds the MS HTML clipboard header to byte array that
     * contains the parameters pairs.
     *
     * The consequence of parameters is fixed, but some or all of them could be
     * omitted. One parameter per one text line.
     * It looks like that:
     *
     * Version:1.0\r\n                -- current supported version
     * StartHTML:000000192\r\n        -- shift in array to the first byte after the header
     * EndHTML:000000757\r\n          -- shift in array of last byte for HTML syntax analysis
     * StartFragment:000000396\r\n    -- shift in array jast after <!--StartFragment-->
     * EndFragment:000000694\r\n      -- shift in array before start  <!--EndFragment-->
     * StartSelection:000000398\r\n   -- shift in array of the first char in copied selection
     * EndSelection:000000692\r\n     -- shift in array of the last char in copied selection
     * SourceURL:http://sun.com/\r\n  -- base URL for related referenses
     * <HTML>..............................
     * ^                                     ^ ^                ^^                                 ^
     * \ StartHTML                           | \-StartSelection | \EndFragment              EndHTML/
     *                                       \-StartFragment    \EndSelection
     *
     *Combinations with tags sequence
     *<!--StartFragment-->......
     * or
     *<HTML>.........
     * are vailid too.
     */
    public static byte[] convertToHTMLFormat(byte[] bytes) {
        // Calculate section offsets
        String htmlPrefix = "";
        String htmlSuffix = "";
        {
            //we have extend the fragment to full HTML document correctly
            //to avoid HTML and BODY tags doubling
            String stContext = new String(bytes);
            String stUpContext = stContext.toUpperCase();
            if( -1 == stUpContext.indexOf("<HTML") ) {
                htmlPrefix = "<HTML>";
                htmlSuffix = "</HTML>";
                if( -1 == stUpContext.indexOf("<BODY") ) {
                    htmlPrefix = htmlPrefix +"<BODY>";
                    htmlSuffix = "</BODY>" + htmlSuffix;
                };
            };
        }

        String stBaseUrl = DEF_SOURCE_URL;
        int nStartHTML =
                VERSION.length() + VERSION_NUM.length() + EOLN.length()
                        + START_HTML.length() + PADDED_WIDTH + EOLN.length()
                        + END_HTML.length() + PADDED_WIDTH + EOLN.length()
                        + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
                        + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
                        + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length()
                ;
        int nStartFragment = nStartHTML + htmlPrefix.length();
        int nEndFragment = nStartFragment + bytes.length - 1;
        int nEndHTML = nEndFragment + htmlSuffix.length();

        StringBuilder header = new StringBuilder(
                nStartFragment
                        + START_FRAGMENT_CMT.length()
        );
        //header
        header.append(VERSION);
        header.append(VERSION_NUM);
        header.append(EOLN);

        header.append(START_HTML);
        header.append(toPaddedString(nStartHTML, PADDED_WIDTH));
        header.append(EOLN);

        header.append(END_HTML);
        header.append(toPaddedString(nEndHTML, PADDED_WIDTH));
        header.append(EOLN);

        header.append(START_FRAGMENT);
        header.append(toPaddedString(nStartFragment, PADDED_WIDTH));
        header.append(EOLN);

        header.append(END_FRAGMENT);
        header.append(toPaddedString(nEndFragment, PADDED_WIDTH));
        header.append(EOLN);

        header.append(SOURCE_URL);
        header.append(stBaseUrl);
        header.append(EOLN);

        //HTML
        header.append(htmlPrefix);

        byte[] headerBytes = null, trailerBytes = null;

        try {
            headerBytes = header.toString().getBytes(ENCODING);
            trailerBytes = htmlSuffix.getBytes(ENCODING);
        } catch (UnsupportedEncodingException cannotHappen) {
        }

        byte[] retval = new byte[headerBytes.length + bytes.length +
                trailerBytes.length];

        System.arraycopy(headerBytes, 0, retval, 0, headerBytes.length);
        System.arraycopy(bytes, 0, retval, headerBytes.length,
                bytes.length - 1);
        System.arraycopy(trailerBytes, 0, retval,
                headerBytes.length + bytes.length - 1,
                trailerBytes.length);
        retval[retval.length-1] = 0;

        return retval;
    }

    ////////////////////////////////////
    //decoder instance data and methods:

    private final BufferedInputStream bufferedStream;
    private boolean descriptionParsed = false;
    private boolean closed = false;

    // InputStreamReader uses an 8K buffer. The size is not customizable.
    public static final int BYTE_BUFFER_LEN = 8192;

    // CharToByteUTF8.getMaxBytesPerChar returns 3, so we should not buffer
    // more chars than 3 times the number of bytes we can buffer.
    public static final int CHAR_BUFFER_LEN = BYTE_BUFFER_LEN / 3;

    private static final String FAILURE_MSG =
            "Unable to parse HTML description: ";
    private static final String INVALID_MSG =
            " invalid";

    //HTML header mapping:
    private long   iHTMLStart,// StartHTML -- shift in array to the first byte after the header
            iHTMLEnd,  // EndHTML -- shift in array of last byte for HTML syntax analysis
            iFragStart,// StartFragment -- shift in array jast after <!--StartFragment-->
            iFragEnd,  // EndFragment -- shift in array before start <!--EndFragment-->
            iSelStart, // StartSelection -- shift in array of the first char in copied selection
            iSelEnd;   // EndSelection -- shift in array of the last char in copied selection
    private String stBaseURL; // SourceURL -- base URL for related referenses
    private String stVersion; // Version -- current supported version

    //Stream reader markers:
    private long iStartOffset,
            iEndOffset,
            iReadCount;

    private EHTMLReadMode readMode;

    public HTMLCodec(
            InputStream _bytestream,
            EHTMLReadMode _readMode) throws IOException
    {
        bufferedStream = new BufferedInputStream(_bytestream, BYTE_BUFFER_LEN);
        readMode = _readMode;
    }

    public synchronized String getBaseURL() throws IOException
    {
        if( !descriptionParsed ) {
            parseDescription();
        }
        return stBaseURL;
    }
    public synchronized String getVersion() throws IOException
    {
        if( !descriptionParsed ) {
            parseDescription();
        }
        return stVersion;
    }

    /**
     * parseDescription parsing HTML clipboard header as it described in
     * comment to convertToHTMLFormat
     */
    private void parseDescription() throws IOException
    {
        stBaseURL = null;
        stVersion = null;

        // initialization of array offset pointers
        // to the same "uninitialized" state.
        iHTMLEnd =
                iHTMLStart =
                        iFragEnd =
                                iFragStart =
                                        iSelEnd =
                                                iSelStart = -1;

        bufferedStream.mark(BYTE_BUFFER_LEN);
        String astEntries[] = new String[] {
                //common
                VERSION,
                START_HTML,
                END_HTML,
                START_FRAGMENT,
                END_FRAGMENT,
                //ver 1.0
                START_SELECTION,
                END_SELECTION,
                SOURCE_URL
        };
        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(
                        bufferedStream,
                        ENCODING
                ),
                CHAR_BUFFER_LEN
        );
        long iHeadSize = 0;
        long iCRSize = EOLN.length();
        int iEntCount = astEntries.length;
        boolean bContinue = true;

        for( int  iEntry = 0; iEntry < iEntCount; ++iEntry ){
            String stLine = bufferedReader.readLine();
            if( null==stLine ) {
                break;
            }
            //some header entries are optional, but the order is fixed.
            for( ; iEntry < iEntCount; ++iEntry ){
                if( !stLine.startsWith(astEntries[iEntry]) ) {
                    continue;
                }
                iHeadSize += stLine.length() + iCRSize;
                String stValue = stLine.substring(astEntries[iEntry].length()).trim();
                if( null!=stValue ) {
                    try{
                        switch( iEntry ){
                            case 0:
                                stVersion = stValue;
                                break;
                            case 1:
                                iHTMLStart = Integer.parseInt(stValue);
                                break;
                            case 2:
                                iHTMLEnd = Integer.parseInt(stValue);
                                break;
                            case 3:
                                iFragStart = Integer.parseInt(stValue);
                                break;
                            case 4:
                                iFragEnd = Integer.parseInt(stValue);
                                break;
                            case 5:
                                iSelStart = Integer.parseInt(stValue);
                                break;
                            case 6:
                                iSelEnd = Integer.parseInt(stValue);
                                break;
                            case 7:
                                stBaseURL = stValue;
                                break;
                        };
                    } catch ( NumberFormatException e ) {
                        throw new IOException(FAILURE_MSG + astEntries[iEntry]+ " value " + e + INVALID_MSG);
                    }
                }
                break;
            }
        }
        //some entries could absent in HTML header,
        //so we have find they by another way.
        if( -1 == iHTMLStart )
            iHTMLStart = iHeadSize;
        if( -1 == iFragStart )
            iFragStart = iHTMLStart;
        if( -1 == iFragEnd )
            iFragEnd = iHTMLEnd;
        if( -1 == iSelStart )
            iSelStart = iFragStart;
        if( -1 == iSelEnd )
            iSelEnd = iFragEnd;

        //one of possible modes
        switch( readMode ){
            case HTML_READ_ALL:
                iStartOffset = iHTMLStart;
                iEndOffset = iHTMLEnd;
                break;
            case HTML_READ_FRAGMENT:
                iStartOffset = iFragStart;
                iEndOffset = iFragEnd;
                break;
            case HTML_READ_SELECTION:
            default:
                iStartOffset = iSelStart;
                iEndOffset = iSelEnd;
                break;
        }

        bufferedStream.reset();
        if( -1 == iStartOffset ){
            throw new IOException(FAILURE_MSG + "invalid HTML format.");
        }

        int curOffset = 0;
        while (curOffset < iStartOffset){
            curOffset += bufferedStream.skip(iStartOffset - curOffset);
        }

        iReadCount = curOffset;

        if( iStartOffset != iReadCount ){
            throw new IOException(FAILURE_MSG + "Byte stream ends in description.");
        }
        descriptionParsed = true;
    }

    public synchronized int read() throws IOException {
        if( closed ){
            throw new IOException("Stream closed");
        }

        if( !descriptionParsed ){
            parseDescription();
        }
        if( -1 != iEndOffset && iReadCount >= iEndOffset ) {
            return -1;
        }

        int retval = bufferedStream.read();
        if( retval == -1 ) {
            return -1;
        }
        ++iReadCount;
        return retval;
    }

    public synchronized void close() throws IOException {
        if( !closed ){
            closed = true;
            bufferedStream.close();
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java WDataTransferer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.