Java Clipboard: Вставить HTML из Firefox в Linux - программирование
Подтвердить что ты не робот

Java Clipboard: Вставить HTML из Firefox в Linux

У меня странная проблема при вставке HTML из Firefox в приложение Java6 (только!) в Linux. Вот минимальный пример:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.io.Reader;
import java.nio.ByteBuffer;

class ClipboardPrinter {
    public static void main( String args[] ) throws Exception
    {
        Clipboard systemClipboard = Toolkit.getDefaultToolkit()
                .getSystemClipboard();
        Transferable transferData = systemClipboard.getContents(null);
        if (transferData == null) {
            System.out.println("no content");
            return;
        }

//      final DataFlavor htmlFlavorString = new DataFlavor("text/html;class=java.lang.String");
//      String html = (String)transferData.getTransferData(htmlFlavorString);
//      System.out.println("html = '" + html + "'");

        final DataFlavor htmlFlavor = new DataFlavor("text/html;class=java.nio.ByteBuffer;charset=US-ASCII");
        if (!transferData.isDataFlavorSupported(htmlFlavor)) {
            System.out.println("no text/html reader content");
            return;
        }

        ByteBuffer bb = (ByteBuffer)transferData.getTransferData(htmlFlavor);
        byte[] bytes = bb.array();
        for (byte b: bytes)
        {
            System.out.format("%02x", b);
        }
        System.out.println();
        final int cutoff = 2;
        byte[] bytes2 = new byte[bytes.length - cutoff];
        for (int i = cutoff; i < bytes.length; i++)
            bytes2[i-cutoff] = bytes[i];
        final String htmlContent = new String(bytes2, "UTF-16LE");


        System.out.println("htmlContent = '" + htmlContent + "'");
    }
}

Сначала я попытался использовать new DataFlavor("text/html;class=java.lang.String"), (код прокомментирован в приведенном выше фрагменте), но это приводит к непригодному использованию Строка с 2 символами со значением 65533 в начале (и это не помогает отрезать эти два символа).

Далее я использовал атрибут данных ByteBuffer с charset=US-ASCII (я использовал ASCII по назначению!): charset=UTF-16LE (или UTF-16 или UTF-16BE) не работает на все. С приведенным выше решением charset=US-ASCII (наряду с new String(bytes2, "UTF-16LE")) работают 7-битные символы (но, например, умлауты не работа, '?' вместо этого печатается).

Я отключил два байта, потому что, кажется, в начале два баса (не конечно, может быть что-то еще)?

Я получаю аналогичный результат с ароматом данных с charset=UTF-8 и cutoff = 6 (два трехбайтных "замещающих символа" 0xEFBFBD на начало и умлаут закодированы как два неправильных символа). В обоих случаев я использовал new String(bytes2, "UTF-16LE").

Есть ли у вас какие-либо предложения о том, как:

  • поддерживать не-ASCII символы в этом решении (или найти лучшее решение)?
  • определить, UTF-16LE или UTF-16BE?

Спасибо! Любые подсказки приветствуются!

BTW: Вот поддерживаемые параметры данных в моей (Linux) системе (от transferable.getTransferDataFlavors()):

[java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.Reader]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.lang.String]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.CharBuffer]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[C]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=UTF-16]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=UTF-16]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=java.lang.String]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.Reader]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.lang.String]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.CharBuffer]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[C]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=unicode]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=UTF-16]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=UTF-16]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=UTF-8]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=UTF-16BE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=UTF-16LE]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=ISO-8859-1]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.InputStream;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.nio.ByteBuffer;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=[B;charset=US-ASCII]
java.awt.datatransfer.DataFlavor[mimetype=text/x-moz-url-priv;representationclass=java.io.InputStream]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlinfo;representationclass=java.io.InputStream]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlcontext;representationclass=java.io.InputStream]
java.awt.datatransfer.DataFlavor[mimetype=text/x-moz-url-priv;representationclass=java.nio.ByteBuffer]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlinfo;representationclass=java.nio.ByteBuffer]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlcontext;representationclass=java.nio.ByteBuffer]
java.awt.datatransfer.DataFlavor[mimetype=text/x-moz-url-priv;representationclass=[B]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlinfo;representationclass=[B]
java.awt.datatransfer.DataFlavor[mimetype=text/_moz_htmlcontext;representationclass=[B]]
4b9b3361

Ответ 1

Я считаю, что проблема связана с тем, что он read from clipboard as US-ASCII, а затем конвертируется в Юникод и ожидает, что немецкие умлауты не пострадают. Поскольку US-ASCII представляет собой 7-битную кодировку, немецкие умлауты не включаются и уже потеряны после прочтения буфера обмена как US-ASCII.

public class CharsetDemo {
    public static void main(String[] args) throws Exception {
        byte[] bytes;

        // convert the German umlaut to bytes in US-ASCII charset
        bytes = "ö".getBytes("US-ASCII");
        System.out.println("US-ASCII");
        System.out.println("bytes : " + asHexString(bytes));
        System.out.println("string: " + new String(bytes, "US-ASCII"));
        System.out.println();

        // create a unicode string from the US-ASCII bytes
        String utf8String = new String(bytes, "UTF-8");
        bytes = utf8String.getBytes("UTF-8");
        System.out.println("UTF-8");
        System.out.println("bytes : " + asHexString(bytes));
        System.out.println("string: " + utf8String);
        System.out.println();

        // convert the German umlaut to bytes in ISO-8859-1 charset
        bytes = "ö".getBytes("ISO-8859-1");
        System.out.println("ISO 8859-1");
        System.out.println("bytes : " + asHexString(bytes));
        System.out.println("string: " + new String(bytes, "ISO-8859-1"));
        System.out.println();

        // create a unicode string from the ISO-8859-1 bytes
        utf8String = new String(bytes, "UTF-8");
        bytes = utf8String.getBytes("UTF-8");
        System.out.println("UTF-8");
        System.out.println("bytes : " + asHexString(bytes));
        System.out.println("string: " + utf8String);
        System.out.println();

        // bytes of the "REPLACEMET CHARACTER"
        System.out.println("replacement character bytes: " 
            + asHexString("\uFFFD".getBytes("UTF-8")));

    }

    static String asHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%X ", b));
        }
        return sb.toString();
    }
}

Выход

US-ASCII
bytes : 3F 
string: ?  <--- the question mark represents here the "REPLACEMENT CHARACTER"

UTF-8
bytes : 3F 
string: ?

ISO 8859-1
bytes : F6 
string: ö

UTF-8
bytes : EF BF BD  <-- the "REPLACEMENT CHARACTER", as "F6" is not a valid UTF-8 codepoint
string: �

replacement character bytes: EF BF BD