12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.awt.X11;
27
28 import java.awt.Image;
29
30 import java.awt.datatransfer.DataFlavor;
31 import java.awt.datatransfer.Transferable;
32 import java.awt.datatransfer.UnsupportedFlavorException;
33
34 import java.awt.image.BufferedImage;
35 import java.awt.image.ColorModel;
36 import java.awt.image.WritableRaster;
37
38 import java.io.BufferedReader;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.io.IOException;
42
43 import java.net.URI;
44 import java.net.URISyntaxException;
45
46 import java.util.ArrayList;
47 import java.util.Iterator;
48 import java.util.LinkedHashSet;
49 import java.util.List;
50
51 import javax.imageio.ImageIO;
52 import javax.imageio.ImageReader;
53 import javax.imageio.ImageTypeSpecifier;
54 import javax.imageio.ImageWriter;
55 import javax.imageio.spi.ImageWriterSpi;
56
57 import sun.awt.datatransfer.DataTransferer;
58 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
59
60 import java.io.ByteArrayOutputStream;
61 import java.util.stream.Stream;
62
63 /**
64 * Platform-specific support for the data transfer subsystem.
65 */
66 public class XDataTransferer extends DataTransferer {
67 static final XAtom FILE_NAME_ATOM = XAtom.get("FILE_NAME");
68 static final XAtom DT_NET_FILE_ATOM = XAtom.get("_DT_NETFILE");
69 static final XAtom PNG_ATOM = XAtom.get("PNG");
70 static final XAtom JFIF_ATOM = XAtom.get("JFIF");
71 static final XAtom TARGETS_ATOM = XAtom.get("TARGETS");
72 static final XAtom INCR_ATOM = XAtom.get("INCR");
73 static final XAtom MULTIPLE_ATOM = XAtom.get("MULTIPLE");
74
75 /**
76 * Singleton constructor
77 */
78 private XDataTransferer() {
79 }
80
81 private static XDataTransferer transferer;
82
83 static synchronized XDataTransferer getInstanceImpl() {
84 if (transferer == null) {
85 transferer = new XDataTransferer();
86 }
87 return transferer;
88 }
89
90 public String getDefaultUnicodeEncoding() {
91 return "iso-10646-ucs-2";
92 }
93
94 public boolean isLocaleDependentTextFormat(long format) {
95 return false;
96 }
97
98 public boolean isTextFormat(long format) {
99 return super.isTextFormat(format)
100 || isMimeFormat(format, "text");
101 }
102
103 protected String getCharsetForTextFormat(Long lFormat) {
104 long format = lFormat.longValue();
105 if (isMimeFormat(format, "text")) {
106 String nat = getNativeForFormat(format);
107 DataFlavor df = new DataFlavor(nat, null);
108 // Ignore the charset parameter of the MIME type if the subtype
109 // doesn't support charset.
110 if (!DataTransferer.doesSubtypeSupportCharset(df)) {
111 return null;
112 }
113 String charset = df.getParameter("charset");
114 if (charset != null) {
115 return charset;
116 }
117 }
118 return super.getCharsetForTextFormat(lFormat);
119 }
120
121 protected boolean isURIListFormat(long format) {
122 String nat = getNativeForFormat(format);
123 if (nat == null) {
124 return false;
125 }
126 try {
127 DataFlavor df = new DataFlavor(nat);
128 if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
129 return true;
130 }
131 } catch (Exception e) {
132 // Not a MIME format.
133 }
134 return false;
135 }
136
137 public boolean isFileFormat(long format) {
138 return format == FILE_NAME_ATOM.getAtom() ||
139 format == DT_NET_FILE_ATOM.getAtom();
140 }
141
142 public boolean isImageFormat(long format) {
143 return format == PNG_ATOM.getAtom() ||
144 format == JFIF_ATOM.getAtom() ||
145 isMimeFormat(format, "image");
146 }
147
148 protected Long getFormatForNativeAsLong(String str) {
149 // Just get the atom. If it has already been retrived
150 // once, we'll get a copy so this should be very fast.
151 long atom = XAtom.get(str).getAtom();
152 return Long.valueOf(atom);
153 }
154
155 protected String getNativeForFormat(long format) {
156 return getTargetNameForAtom(format);
157 }
158
159 public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
160 return XToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();
161 }
162
163 /**
164 * Gets an format name for a given format (atom)
165 */
166 private String getTargetNameForAtom(long atom) {
167 return XAtom.get(atom).getName();
168 }
169
170 protected byte[] imageToPlatformBytes(Image image, long format)
171 throws IOException {
172 String mimeType = null;
173 if (format == PNG_ATOM.getAtom()) {
174 mimeType = "image/png";
175 } else if (format == JFIF_ATOM.getAtom()) {
176 mimeType = "image/jpeg";
177 } else {
178 // Check if an image MIME format.
179 try {
180 String nat = getNativeForFormat(format);
181 DataFlavor df = new DataFlavor(nat);
182 String primaryType = df.getPrimaryType();
183 if ("image".equals(primaryType)) {
184 mimeType = df.getPrimaryType() + "/" + df.getSubType();
185 }
186 } catch (Exception e) {
187 // Not an image MIME format.
188 }
189 }
190 if (mimeType != null) {
191 return imageToStandardBytes(image, mimeType);
192 } else {
193 String nativeFormat = getNativeForFormat(format);
194 throw new IOException("Translation to " + nativeFormat +
195 " is not supported.");
196 }
197 }
198
199 protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
200 throws IOException
201 {
202 ByteArrayOutputStream bos = new ByteArrayOutputStream();
203 for (int i = 0; i < fileList.size(); i++)
204 {
205 byte[] bytes = fileList.get(i).getBytes();
206 if (i != 0) bos.write(0);
207 bos.write(bytes, 0, bytes.length);
208 }
209 return bos;
210 }
211
212 /**
213 * Translates either a byte array or an input stream which contain
214 * platform-specific image data in the given format into an Image.
215 */
216 protected Image platformImageBytesToImage(
217 byte[] bytes, long format) throws IOException
218 {
219 String mimeType = null;
220 if (format == PNG_ATOM.getAtom()) {
221 mimeType = "image/png";
222 } else if (format == JFIF_ATOM.getAtom()) {
223 mimeType = "image/jpeg";
224 } else {
225 // Check if an image MIME format.
226 try {
227 String nat = getNativeForFormat(format);
228 DataFlavor df = new DataFlavor(nat);
229 String primaryType = df.getPrimaryType();
230 if ("image".equals(primaryType)) {
231 mimeType = df.getPrimaryType() + "/" + df.getSubType();
232 }
233 } catch (Exception e) {
234 // Not an image MIME format.
235 }
300
301 return false;
302 }
303
304 /*
305 * The XDnD protocol prescribes that the Atoms used as targets for data
306 * transfer should have string names that represent the corresponding MIME
307 * types.
308 * To meet this requirement we check if the passed native format constitutes
309 * a valid MIME and return a list of flavors to which the data in this MIME
310 * type can be translated by the Data Transfer subsystem.
311 */
312 @Override
313 public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
314 LinkedHashSet<DataFlavor> flavors = new LinkedHashSet<>();
315
316 if (nat == null) {
317 return flavors;
318 }
319
320 DataFlavor df = null;
321
322 try {
323 df = new DataFlavor(nat);
324 } catch (Exception e) {
325 // The string doesn't constitute a valid MIME type.
326 return flavors;
327 }
328
329 DataFlavor value = df;
330 final String primaryType = df.getPrimaryType();
331 final String baseType = primaryType + "/" + df.getSubType();
332
333 // For text formats we map natives to MIME strings instead of data
334 // flavors to enable dynamic text native-to-flavor mapping generation.
335 // See SystemFlavorMap.getFlavorsForNative() for details.
336 if ("image".equals(primaryType)) {
337 Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(baseType);
338 if (readers.hasNext()) {
339 flavors.add(DataFlavor.imageFlavor);
340 }
341 }
366 /*
367 * The XDnD protocol prescribes that the Atoms used as targets for data
368 * transfer should have string names that represent the corresponding MIME
369 * types.
370 * To meet this requirement we return a list of formats that represent
371 * MIME types to which the data in this flavor can be translated by the Data
372 * Transfer subsystem.
373 */
374 @Override
375 public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
376 LinkedHashSet<String> natives = new LinkedHashSet<>(1);
377
378 if (df == null) {
379 return natives;
380 }
381
382 String charset = df.getParameter("charset");
383 String baseType = df.getPrimaryType() + "/" + df.getSubType();
384 String mimeType = baseType;
385
386 if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) {
387 mimeType += ";charset=" + charset;
388 }
389
390 // Add a mapping to the MIME native whenever the representation class
391 // doesn't require translation.
392 if (df.getRepresentationClass() != null &&
393 (df.isRepresentationClassInputStream() ||
394 df.isRepresentationClassByteBuffer() ||
395 byte[].class.equals(df.getRepresentationClass()))) {
396 natives.add(mimeType);
397 }
398
399 if (DataFlavor.imageFlavor.equals(df)) {
400 String[] mimeTypes = ImageIO.getWriterMIMETypes();
401 if (mimeTypes != null) {
402 for (String mime : mimeTypes) {
403 Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType(mime);
404 while (writers.hasNext()) {
405 ImageWriter imageWriter = writers.next();
406 ImageWriterSpi writerSpi = imageWriter.getOriginatingProvider();
407
408 if (writerSpi != null &&
409 writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) {
410 natives.add(mime);
411 break;
412 }
413 }
414 }
415 }
416 } else if (DataTransferer.isFlavorCharsetTextType(df)) {
417 // stringFlavor is semantically equivalent to the standard
418 // "text/plain" MIME type.
419 if (DataFlavor.stringFlavor.equals(df)) {
420 baseType = "text/plain";
421 }
422
423 for (String encoding : DataTransferer.standardEncodings()) {
424 if (!encoding.equals(charset)) {
425 natives.add(baseType + ";charset=" + encoding);
426 }
427 }
428
429 // Add a MIME format without specified charset.
430 if (!natives.contains(baseType)) {
431 natives.add(baseType);
432 }
433 }
434
435 return natives;
436 }
437 }
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.awt.X11;
27
28 import java.awt.Image;
29
30 import java.awt.datatransfer.DataFlavor;
31 import java.awt.datatransfer.Transferable;
32
33 import java.awt.image.BufferedImage;
34 import java.awt.image.ColorModel;
35 import java.awt.image.WritableRaster;
36
37 import java.io.BufferedReader;
38 import java.io.InputStream;
39 import java.io.InputStreamReader;
40 import java.io.IOException;
41
42 import java.net.URI;
43 import java.net.URISyntaxException;
44
45 import java.util.ArrayList;
46 import java.util.Iterator;
47 import java.util.LinkedHashSet;
48
49 import javax.imageio.ImageIO;
50 import javax.imageio.ImageReader;
51 import javax.imageio.ImageTypeSpecifier;
52 import javax.imageio.ImageWriter;
53 import javax.imageio.spi.ImageWriterSpi;
54
55 import sun.datatransfer.DataFlavorUtil;
56 import sun.awt.datatransfer.DataTransferer;
57 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
58
59 import java.io.ByteArrayOutputStream;
60
61 /**
62 * Platform-specific support for the data transfer subsystem.
63 */
64 public class XDataTransferer extends DataTransferer {
65 static final XAtom FILE_NAME_ATOM = XAtom.get("FILE_NAME");
66 static final XAtom DT_NET_FILE_ATOM = XAtom.get("_DT_NETFILE");
67 static final XAtom PNG_ATOM = XAtom.get("PNG");
68 static final XAtom JFIF_ATOM = XAtom.get("JFIF");
69 static final XAtom TARGETS_ATOM = XAtom.get("TARGETS");
70 static final XAtom INCR_ATOM = XAtom.get("INCR");
71 static final XAtom MULTIPLE_ATOM = XAtom.get("MULTIPLE");
72
73 /**
74 * Singleton constructor
75 */
76 private XDataTransferer() {
77 }
78
79 private static XDataTransferer transferer;
80
81 static synchronized XDataTransferer getInstanceImpl() {
82 if (transferer == null) {
83 transferer = new XDataTransferer();
84 }
85 return transferer;
86 }
87
88 @Override
89 public String getDefaultUnicodeEncoding() {
90 return "iso-10646-ucs-2";
91 }
92
93 @Override
94 public boolean isLocaleDependentTextFormat(long format) {
95 return false;
96 }
97
98 @Override
99 public boolean isTextFormat(long format) {
100 return super.isTextFormat(format)
101 || isMimeFormat(format, "text");
102 }
103
104 @Override
105 protected String getCharsetForTextFormat(Long lFormat) {
106 if (isMimeFormat(lFormat, "text")) {
107 String nat = getNativeForFormat(lFormat);
108 DataFlavor df = new DataFlavor(nat, null);
109 // Ignore the charset parameter of the MIME type if the subtype
110 // doesn't support charset.
111 if (!DataFlavorUtil.doesSubtypeSupportCharset(df)) {
112 return null;
113 }
114 String charset = df.getParameter("charset");
115 if (charset != null) {
116 return charset;
117 }
118 }
119 return super.getCharsetForTextFormat(lFormat);
120 }
121
122 @Override
123 protected boolean isURIListFormat(long format) {
124 String nat = getNativeForFormat(format);
125 if (nat == null) {
126 return false;
127 }
128 try {
129 DataFlavor df = new DataFlavor(nat);
130 if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
131 return true;
132 }
133 } catch (Exception e) {
134 // Not a MIME format.
135 }
136 return false;
137 }
138
139 @Override
140 public boolean isFileFormat(long format) {
141 return format == FILE_NAME_ATOM.getAtom() ||
142 format == DT_NET_FILE_ATOM.getAtom();
143 }
144
145 @Override
146 public boolean isImageFormat(long format) {
147 return format == PNG_ATOM.getAtom() ||
148 format == JFIF_ATOM.getAtom() ||
149 isMimeFormat(format, "image");
150 }
151
152 @Override
153 protected Long getFormatForNativeAsLong(String str) {
154 // Just get the atom. If it has already been retrived
155 // once, we'll get a copy so this should be very fast.
156 return XAtom.get(str).getAtom();
157 }
158
159 @Override
160 protected String getNativeForFormat(long format) {
161 return getTargetNameForAtom(format);
162 }
163
164 public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
165 return XToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();
166 }
167
168 /**
169 * Gets an format name for a given format (atom)
170 */
171 private String getTargetNameForAtom(long atom) {
172 return XAtom.get(atom).getName();
173 }
174
175 @Override
176 protected byte[] imageToPlatformBytes(Image image, long format)
177 throws IOException {
178 String mimeType = null;
179 if (format == PNG_ATOM.getAtom()) {
180 mimeType = "image/png";
181 } else if (format == JFIF_ATOM.getAtom()) {
182 mimeType = "image/jpeg";
183 } else {
184 // Check if an image MIME format.
185 try {
186 String nat = getNativeForFormat(format);
187 DataFlavor df = new DataFlavor(nat);
188 String primaryType = df.getPrimaryType();
189 if ("image".equals(primaryType)) {
190 mimeType = df.getPrimaryType() + "/" + df.getSubType();
191 }
192 } catch (Exception e) {
193 // Not an image MIME format.
194 }
195 }
196 if (mimeType != null) {
197 return imageToStandardBytes(image, mimeType);
198 } else {
199 String nativeFormat = getNativeForFormat(format);
200 throw new IOException("Translation to " + nativeFormat +
201 " is not supported.");
202 }
203 }
204
205 @Override
206 protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
207 throws IOException
208 {
209 ByteArrayOutputStream bos = new ByteArrayOutputStream();
210 for (int i = 0; i < fileList.size(); i++)
211 {
212 byte[] bytes = fileList.get(i).getBytes();
213 if (i != 0) bos.write(0);
214 bos.write(bytes, 0, bytes.length);
215 }
216 return bos;
217 }
218
219 /**
220 * Translates either a byte array or an input stream which contain
221 * platform-specific image data in the given format into an Image.
222 */
223 @Override
224 protected Image platformImageBytesToImage(
225 byte[] bytes, long format) throws IOException
226 {
227 String mimeType = null;
228 if (format == PNG_ATOM.getAtom()) {
229 mimeType = "image/png";
230 } else if (format == JFIF_ATOM.getAtom()) {
231 mimeType = "image/jpeg";
232 } else {
233 // Check if an image MIME format.
234 try {
235 String nat = getNativeForFormat(format);
236 DataFlavor df = new DataFlavor(nat);
237 String primaryType = df.getPrimaryType();
238 if ("image".equals(primaryType)) {
239 mimeType = df.getPrimaryType() + "/" + df.getSubType();
240 }
241 } catch (Exception e) {
242 // Not an image MIME format.
243 }
308
309 return false;
310 }
311
312 /*
313 * The XDnD protocol prescribes that the Atoms used as targets for data
314 * transfer should have string names that represent the corresponding MIME
315 * types.
316 * To meet this requirement we check if the passed native format constitutes
317 * a valid MIME and return a list of flavors to which the data in this MIME
318 * type can be translated by the Data Transfer subsystem.
319 */
320 @Override
321 public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
322 LinkedHashSet<DataFlavor> flavors = new LinkedHashSet<>();
323
324 if (nat == null) {
325 return flavors;
326 }
327
328 DataFlavor df;
329 try {
330 df = new DataFlavor(nat);
331 } catch (Exception e) {
332 // The string doesn't constitute a valid MIME type.
333 return flavors;
334 }
335
336 DataFlavor value = df;
337 final String primaryType = df.getPrimaryType();
338 final String baseType = primaryType + "/" + df.getSubType();
339
340 // For text formats we map natives to MIME strings instead of data
341 // flavors to enable dynamic text native-to-flavor mapping generation.
342 // See SystemFlavorMap.getFlavorsForNative() for details.
343 if ("image".equals(primaryType)) {
344 Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(baseType);
345 if (readers.hasNext()) {
346 flavors.add(DataFlavor.imageFlavor);
347 }
348 }
373 /*
374 * The XDnD protocol prescribes that the Atoms used as targets for data
375 * transfer should have string names that represent the corresponding MIME
376 * types.
377 * To meet this requirement we return a list of formats that represent
378 * MIME types to which the data in this flavor can be translated by the Data
379 * Transfer subsystem.
380 */
381 @Override
382 public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
383 LinkedHashSet<String> natives = new LinkedHashSet<>(1);
384
385 if (df == null) {
386 return natives;
387 }
388
389 String charset = df.getParameter("charset");
390 String baseType = df.getPrimaryType() + "/" + df.getSubType();
391 String mimeType = baseType;
392
393 if (charset != null && DataFlavorUtil.isFlavorCharsetTextType(df)) {
394 mimeType += ";charset=" + charset;
395 }
396
397 // Add a mapping to the MIME native whenever the representation class
398 // doesn't require translation.
399 if (df.getRepresentationClass() != null &&
400 (df.isRepresentationClassInputStream() ||
401 df.isRepresentationClassByteBuffer() ||
402 byte[].class.equals(df.getRepresentationClass()))) {
403 natives.add(mimeType);
404 }
405
406 if (DataFlavor.imageFlavor.equals(df)) {
407 String[] mimeTypes = ImageIO.getWriterMIMETypes();
408 if (mimeTypes != null) {
409 for (String mime : mimeTypes) {
410 Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType(mime);
411 while (writers.hasNext()) {
412 ImageWriter imageWriter = writers.next();
413 ImageWriterSpi writerSpi = imageWriter.getOriginatingProvider();
414
415 if (writerSpi != null &&
416 writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) {
417 natives.add(mime);
418 break;
419 }
420 }
421 }
422 }
423 } else if (DataFlavorUtil.isFlavorCharsetTextType(df)) {
424 // stringFlavor is semantically equivalent to the standard
425 // "text/plain" MIME type.
426 if (DataFlavor.stringFlavor.equals(df)) {
427 baseType = "text/plain";
428 }
429
430 for (String encoding : DataFlavorUtil.standardEncodings()) {
431 if (!encoding.equals(charset)) {
432 natives.add(baseType + ";charset=" + encoding);
433 }
434 }
435
436 // Add a MIME format without specified charset.
437 if (!natives.contains(baseType)) {
438 natives.add(baseType);
439 }
440 }
441
442 return natives;
443 }
444 }
|