package sun.lwawt.macosx;
import java.awt.*;
import java.awt.image.*;
import sun.awt.image.ImageRepresentation;
import java.io.*;
import java.net.URL;
import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.*;
import java.awt.datatransfer.*;
import sun.awt.datatransfer.*;
public class CDataTransferer extends DataTransferer {
private static final Map<String, Long> predefinedClipboardNameMap;
private static final Map<Long, String> predefinedClipboardFormatMap;
private static final String[] predefinedClipboardNames = {
"",
"STRING",
"FILE_NAME",
"TIFF",
"RICH_TEXT",
"HTML",
"PDF",
"URL"
};
static {
Map<String, Long> nameMap = new HashMap<String, Long>(predefinedClipboardNames.length, 1.0f);
Map<Long, String> formatMap = new HashMap<Long, String>(predefinedClipboardNames.length, 1.0f);
for (int i = 1; i < predefinedClipboardNames.length; i++) {
nameMap.put(predefinedClipboardNames[i], new Long(i));
formatMap.put(new Long(i), predefinedClipboardNames[i]);
}
predefinedClipboardNameMap = Collections.synchronizedMap(nameMap);
predefinedClipboardFormatMap = Collections.synchronizedMap(formatMap);
}
public static final int CF_UNSUPPORTED = 0;
public static final int CF_STRING = 1;
public static final int CF_FILE = 2;
public static final int CF_TIFF = 3;
public static final int CF_RICH_TEXT = 4;
public static final int CF_HTML = 5;
public static final int CF_PDF = 6;
public static final int CF_URL = 7;
public static final int CF_PNG = 10;
public static final int CF_JPEG = 11;
public static final Long L_CF_TIFF = predefinedClipboardNameMap.get(predefinedClipboardNames[CF_TIFF]);
private static final Long[] imageFormats = new Long[] {
L_CF_TIFF
};
private CDataTransferer() {}
private static CDataTransferer fTransferer;
public static synchronized CDataTransferer getInstanceImpl() {
if (fTransferer == null) {
fTransferer = new CDataTransferer();
}
return fTransferer;
}
public String getDefaultUnicodeEncoding() {
return "utf-16le";
}
public boolean isLocaleDependentTextFormat(long format) {
return format == CF_STRING;
}
public boolean isFileFormat(long format) {
return format == CF_FILE;
}
public boolean isImageFormat(long format) {
int ifmt = (int)format;
switch(ifmt) {
case CF_TIFF:
case CF_PDF:
case CF_PNG:
case CF_JPEG:
return true;
default:
return false;
}
}
protected Long[] getImageFormatsAsLongArray() {
return imageFormats;
}
public byte[] translateTransferable(Transferable contents, DataFlavor flavor, long format) throws IOException
{
byte[] bytes = super.translateTransferable(contents, flavor, format);
return bytes;
}
protected Object translateBytesOrStream(InputStream stream, byte[] bytes, DataFlavor flavor, long format,
Transferable transferable) throws IOException
{
if (format == CF_HTML && flavor.isFlavorTextType()) {
if (stream == null) {
stream = new ByteArrayInputStream(bytes);
bytes = null;
}
stream = new HTMLDecodingInputStream(stream);
}
if (format == CF_URL && URL.class.equals(flavor.getRepresentationClass()))
{
if (bytes == null) {
bytes = inputStreamToByteArray(stream);
stream = null;
}
String charset = getDefaultTextCharset();
if (transferable != null && transferable.isDataFlavorSupported(javaTextEncodingFlavor)) {
try {
charset = new String((byte[])transferable.getTransferData(javaTextEncodingFlavor), "UTF-8");
} catch (UnsupportedFlavorException cannotHappen) {
}
}
return new URL(new String(bytes, charset));
}
if (format == CF_STRING) {
bytes = Normalizer.normalize(new String(bytes, "UTF8"), Form.NFC).getBytes("UTF8");
}
return super.translateBytesOrStream(stream, bytes, flavor, format, transferable);
}
synchronized protected Long getFormatForNativeAsLong(String str) {
Long format = predefinedClipboardNameMap.get(str);
if (format == null) {
if (java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) {
return new Long(-1);
}
format = new Long(registerFormatWithPasteboard(str));
predefinedClipboardNameMap.put(str, format);
predefinedClipboardFormatMap.put(format, str);
}
return format;
}
private native long registerFormatWithPasteboard(String type);
private native String formatForIndex(long index);
protected String getNativeForFormat(long format) {
String returnValue = null;
if (format >= 0 && format < predefinedClipboardNames.length) {
returnValue = predefinedClipboardNames[(int) format];
} else {
Long formatObj = new Long(format);
returnValue = predefinedClipboardFormatMap.get(formatObj);
if (returnValue == null) {
returnValue = formatForIndex(format);
if (returnValue != null) {
predefinedClipboardNameMap.put(returnValue, formatObj);
predefinedClipboardFormatMap.put(formatObj, returnValue);
}
}
}
if (returnValue == null) {
returnValue = predefinedClipboardNames[CF_UNSUPPORTED];
}
return returnValue;
}
private final ToolkitThreadBlockedHandler handler = new CToolkitThreadBlockedHandler();
public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
return handler;
}
protected byte[] imageToPlatformBytes(Image image, long format) {
int w = image.getWidth(null);
int h = image.getHeight(null);
BufferedImage bimage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics g = bimage.getGraphics();
g.drawImage(image, 0, 0, w, h, null);
g.dispose();
Raster raster = bimage.getRaster();
DataBuffer buffer = raster.getDataBuffer();
return imageDataToPlatformImageBytes(((DataBufferInt)buffer).getData(),
raster.getWidth(),
raster.getHeight());
}
private static native String[] nativeDragQueryFile(final byte[] bytes);
protected String[] dragQueryFile(final byte[] bytes) {
if (bytes == null) return null;
if (new String(bytes).startsWith("Unsupported type")) return null;
return nativeDragQueryFile(bytes);
}
private native byte[] imageDataToPlatformImageBytes(int[] rData, int nW, int nH);
protected Image platformImageBytesOrStreamToImage(InputStream stream, byte[] bytes, long format) throws IOException {
byte[] imageData = bytes;
if (imageData == null)
imageData = inputStreamToByteArray(stream);
return getImageForByteStream(imageData);
}
private native Image getImageForByteStream(byte[] bytes);
@Override
protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int i = 0; i < fileList.size(); i++)
{
byte[] bytes = fileList.get(i).getBytes();
bos.write(bytes, 0, bytes.length);
bos.write(0);
}
return bos;
}
@Override
protected boolean isURIListFormat(long format) {
String nat = getNativeForFormat(format);
if (nat == null) {
return false;
}
try {
DataFlavor df = new DataFlavor(nat);
if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
return true;
}
} catch (Exception e) {
}
return false;
}
}
final class HTMLSupport {
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_FRAGMENT_CMT = "<!--StartFragment-->";
public static final String END_FRAGMENT_CMT = "<!--EndFragment-->";
public static final String EOLN = "\r\n";
private static final String VERSION_NUM = "0.9";
private static final String HTML_START_END = "-1";
private static final int PADDED_WIDTH = 10;
private static final int =
VERSION.length() + VERSION_NUM.length() + EOLN.length() +
START_HTML.length() + HTML_START_END.length() + EOLN.length() +
END_HTML.length() + HTML_START_END.length() + EOLN.length() +
START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() +
END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() +
START_FRAGMENT_CMT.length() + EOLN.length();
private static final String =
toPaddedString(HEADER_LEN, PADDED_WIDTH);
private static final String TRAILER = END_FRAGMENT_CMT + EOLN + '\0';
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();
buffer.append(array);
buffer.append(string);
string = buffer.toString();
}
return string;
}
public static byte[] convertToHTMLFormat(byte[] bytes) {
StringBuffer header = new StringBuffer(HEADER_LEN);
header.append(VERSION);
header.append(VERSION_NUM);
header.append(EOLN);
header.append(START_HTML);
header.append(HTML_START_END);
header.append(EOLN);
header.append(END_HTML);
header.append(HTML_START_END);
header.append(EOLN);
header.append(START_FRAGMENT);
header.append(HEADER_LEN_STR);
header.append(EOLN);
header.append(END_FRAGMENT);
header.append(toPaddedString(HEADER_LEN + bytes.length - 1,
PADDED_WIDTH));
header.append(EOLN);
header.append(START_FRAGMENT_CMT);
header.append(EOLN);
byte[] headerBytes = null, trailerBytes = null;
try {
headerBytes = new String(header).getBytes(ENCODING);
trailerBytes = TRAILER.getBytes(ENCODING);
} catch (UnsupportedEncodingException cannotHappen) {
}
byte[] retval = new byte[headerBytes.length + bytes.length - 1 +
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);
return retval;
}
}
class HTMLDecodingInputStream extends InputStream {
private final BufferedInputStream bufferedStream;
private boolean descriptionParsed = false;
private boolean closed = false;
private int index;
private int end;
public static final int BYTE_BUFFER_LEN = 8192;
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";
public HTMLDecodingInputStream(InputStream bytestream) throws IOException {
bufferedStream = new BufferedInputStream(bytestream, BYTE_BUFFER_LEN);
}
private void parseDescription() throws IOException {
bufferedStream.mark(BYTE_BUFFER_LEN);
BufferedReader bufferedReader = new BufferedReader
(new InputStreamReader(bufferedStream, HTMLSupport.ENCODING),
CHAR_BUFFER_LEN);
String version = bufferedReader.readLine().trim();
if (version == null || !version.startsWith(HTMLSupport.VERSION)) {
index = 0;
end = -1;
bufferedStream.reset();
return;
}
String input;
boolean startHTML, endHTML, startFragment, endFragment;
startHTML = endHTML = startFragment = endFragment = false;
try {
do {
input = bufferedReader.readLine().trim();
if (input == null) {
close();
throw new IOException(FAILURE_MSG);
} else if (input.startsWith(HTMLSupport.START_HTML)) {
int val = Integer.parseInt
(input.substring(HTMLSupport.START_HTML.length(),
input.length()).trim());
if (val >= 0) {
index = val;
startHTML = true;
} else if (val != -1) {
close();
throw new IOException(FAILURE_MSG +
HTMLSupport.START_HTML +
INVALID_MSG);
}
} else if (input.startsWith(HTMLSupport.END_HTML)) {
int val = Integer.parseInt
(input.substring(HTMLSupport.END_HTML.length(),
input.length()).trim());
if (val >= 0) {
end = val;
endHTML = true;
} else if (val != -1) {
close();
throw new IOException(FAILURE_MSG +
HTMLSupport.END_HTML +
INVALID_MSG);
}
} else if (!startHTML && !endHTML &&
input.startsWith(HTMLSupport.START_FRAGMENT)) {
index = Integer.parseInt
(input.substring(HTMLSupport.START_FRAGMENT.length(),
input.length()).trim());
if (index < 0) {
close();
throw new IOException(FAILURE_MSG +
HTMLSupport.START_FRAGMENT +
INVALID_MSG);
}
startFragment = true;
} else if (!startHTML && !endHTML &&
input.startsWith(HTMLSupport.END_FRAGMENT)) {
end = Integer.parseInt
(input.substring(HTMLSupport.END_FRAGMENT.length(),
input.length()).trim());
if (end < 0) {
close();
throw new IOException(FAILURE_MSG +
HTMLSupport.END_FRAGMENT +
INVALID_MSG);
}
endFragment = true;
}
} while (!((startHTML && endHTML) ||
(startFragment && endFragment)));
} catch (NumberFormatException e) {
close();
throw new IOException(FAILURE_MSG + e);
}
bufferedStream.reset();
for (int i = 0; i < index; i++) {
if (bufferedStream.read() == -1) {
close();
throw new IOException(FAILURE_MSG +
"Byte stream ends in description.");
}
}
}
public int read() throws IOException {
if (closed) {
throw new IOException("Stream closed");
}
if (!descriptionParsed) {
parseDescription();
descriptionParsed = true;
}
if (end != -1 && index >= end) {
return -1;
}
int retval = bufferedStream.read();
if (retval == -1) {
index = end = 0;
return -1;
}
index++;
return retval;
}
public void close() throws IOException {
if (!closed) {
closed = true;
bufferedStream.close();
}
}
}