PageRenderTime 88ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/share/classes/sun/awt/datatransfer/DataTransferer.java

https://bitbucket.org/screenconnect/openjdk8-jdk
Java | 3067 lines | 1902 code | 414 blank | 751 comment | 403 complexity | 8a996103975d531e1bc296128a2fa160 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  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. package sun.awt.datatransfer;
  26. import java.awt.EventQueue;
  27. import java.awt.Graphics;
  28. import java.awt.Image;
  29. import java.awt.Toolkit;
  30. import java.awt.datatransfer.DataFlavor;
  31. import java.awt.datatransfer.FlavorMap;
  32. import java.awt.datatransfer.FlavorTable;
  33. import java.awt.datatransfer.Transferable;
  34. import java.awt.datatransfer.UnsupportedFlavorException;
  35. import java.io.BufferedReader;
  36. import java.io.ByteArrayInputStream;
  37. import java.io.ByteArrayOutputStream;
  38. import java.io.File;
  39. import java.io.InputStream;
  40. import java.io.InputStreamReader;
  41. import java.io.IOException;
  42. import java.io.ObjectInputStream;
  43. import java.io.ObjectOutputStream;
  44. import java.io.Reader;
  45. import java.io.SequenceInputStream;
  46. import java.io.StringReader;
  47. import java.net.URI;
  48. import java.net.URISyntaxException;
  49. import java.nio.ByteBuffer;
  50. import java.nio.CharBuffer;
  51. import java.nio.charset.Charset;
  52. import java.nio.charset.CharsetEncoder;
  53. import java.nio.charset.IllegalCharsetNameException;
  54. import java.nio.charset.UnsupportedCharsetException;
  55. import java.lang.reflect.Constructor;
  56. import java.lang.reflect.InvocationTargetException;
  57. import java.lang.reflect.Method;
  58. import java.lang.reflect.Modifier;
  59. import java.security.AccessController;
  60. import java.security.PrivilegedAction;
  61. import java.security.PrivilegedActionException;
  62. import java.security.PrivilegedExceptionAction;
  63. import java.security.ProtectionDomain;
  64. import java.util.ArrayList;
  65. import java.util.Arrays;
  66. import java.util.Collections;
  67. import java.util.Comparator;
  68. import java.util.HashMap;
  69. import java.util.HashSet;
  70. import java.util.Iterator;
  71. import java.util.LinkedHashSet;
  72. import java.util.List;
  73. import java.util.Map;
  74. import java.util.SortedMap;
  75. import java.util.SortedSet;
  76. import java.util.Set;
  77. import java.util.Stack;
  78. import java.util.TreeMap;
  79. import java.util.TreeSet;
  80. import sun.awt.ComponentFactory;
  81. import sun.util.logging.PlatformLogger;
  82. import sun.awt.AppContext;
  83. import sun.awt.SunToolkit;
  84. import java.awt.image.BufferedImage;
  85. import java.awt.image.ImageObserver;
  86. import java.awt.image.RenderedImage;
  87. import java.awt.image.WritableRaster;
  88. import java.awt.image.ColorModel;
  89. import javax.imageio.ImageIO;
  90. import javax.imageio.ImageReader;
  91. import javax.imageio.ImageReadParam;
  92. import javax.imageio.ImageWriter;
  93. import javax.imageio.ImageTypeSpecifier;
  94. import javax.imageio.spi.ImageWriterSpi;
  95. import javax.imageio.stream.ImageInputStream;
  96. import javax.imageio.stream.ImageOutputStream;
  97. import sun.awt.image.ImageRepresentation;
  98. import sun.awt.image.ToolkitImage;
  99. import java.io.FilePermission;
  100. /**
  101. * Provides a set of functions to be shared among the DataFlavor class and
  102. * platform-specific data transfer implementations.
  103. *
  104. * The concept of "flavors" and "natives" is extended to include "formats",
  105. * which are the numeric values Win32 and X11 use to express particular data
  106. * types. Like FlavorMap, which provides getNativesForFlavors(DataFlavor[]) and
  107. * getFlavorsForNatives(String[]) functions, DataTransferer provides a set
  108. * of getFormatsFor(Transferable|Flavor|Flavors) and
  109. * getFlavorsFor(Format|Formats) functions.
  110. *
  111. * Also provided are functions for translating a Transferable into a byte
  112. * array, given a source DataFlavor and a target format, and for translating
  113. * a byte array or InputStream into an Object, given a source format and
  114. * a target DataFlavor.
  115. *
  116. * @author David Mendenhall
  117. * @author Danila Sinopalnikov
  118. *
  119. * @since 1.3.1
  120. */
  121. public abstract class DataTransferer {
  122. /**
  123. * The <code>DataFlavor</code> representing plain text with Unicode
  124. * encoding, where:
  125. * <pre>
  126. * representationClass = java.lang.String
  127. * mimeType = "text/plain; charset=Unicode"
  128. * </pre>
  129. */
  130. public static final DataFlavor plainTextStringFlavor;
  131. /**
  132. * The <code>DataFlavor</code> representing a Java text encoding String
  133. * encoded in UTF-8, where
  134. * <pre>
  135. * representationClass = [B
  136. * mimeType = "application/x-java-text-encoding"
  137. * </pre>
  138. */
  139. public static final DataFlavor javaTextEncodingFlavor;
  140. /**
  141. * Lazy initialization of Standard Encodings.
  142. */
  143. private static class StandardEncodingsHolder {
  144. private static final SortedSet<String> standardEncodings = load();
  145. private static SortedSet<String> load() {
  146. final Comparator comparator =
  147. new CharsetComparator(IndexedComparator.SELECT_WORST);
  148. final SortedSet<String> tempSet = new TreeSet<String>(comparator);
  149. tempSet.add("US-ASCII");
  150. tempSet.add("ISO-8859-1");
  151. tempSet.add("UTF-8");
  152. tempSet.add("UTF-16BE");
  153. tempSet.add("UTF-16LE");
  154. tempSet.add("UTF-16");
  155. tempSet.add(getDefaultTextCharset());
  156. return Collections.unmodifiableSortedSet(tempSet);
  157. }
  158. }
  159. /**
  160. * Tracks whether a particular text/* MIME type supports the charset
  161. * parameter. The Map is initialized with all of the standard MIME types
  162. * listed in the DataFlavor.selectBestTextFlavor method comment. Additional
  163. * entries may be added during the life of the JRE for text/<other> types.
  164. */
  165. private static final Map textMIMESubtypeCharsetSupport;
  166. /**
  167. * Cache of the platform default encoding as specified in the
  168. * "file.encoding" system property.
  169. */
  170. private static String defaultEncoding;
  171. /**
  172. * A collection of all natives listed in flavormap.properties with
  173. * a primary MIME type of "text".
  174. */
  175. private static final Set textNatives =
  176. Collections.synchronizedSet(new HashSet());
  177. /**
  178. * The native encodings/charsets for the Set of textNatives.
  179. */
  180. private static final Map nativeCharsets =
  181. Collections.synchronizedMap(new HashMap());
  182. /**
  183. * The end-of-line markers for the Set of textNatives.
  184. */
  185. private static final Map nativeEOLNs =
  186. Collections.synchronizedMap(new HashMap());
  187. /**
  188. * The number of terminating NUL bytes for the Set of textNatives.
  189. */
  190. private static final Map nativeTerminators =
  191. Collections.synchronizedMap(new HashMap());
  192. /**
  193. * The key used to store pending data conversion requests for an AppContext.
  194. */
  195. private static final String DATA_CONVERTER_KEY = "DATA_CONVERTER_KEY";
  196. /**
  197. * The singleton DataTransferer instance. It is created during MToolkit
  198. * or WToolkit initialization.
  199. */
  200. private static DataTransferer transferer;
  201. private static final PlatformLogger dtLog = PlatformLogger.getLogger("sun.awt.datatransfer.DataTransfer");
  202. static {
  203. DataFlavor tPlainTextStringFlavor = null;
  204. try {
  205. tPlainTextStringFlavor = new DataFlavor
  206. ("text/plain;charset=Unicode;class=java.lang.String");
  207. } catch (ClassNotFoundException cannotHappen) {
  208. }
  209. plainTextStringFlavor = tPlainTextStringFlavor;
  210. DataFlavor tJavaTextEncodingFlavor = null;
  211. try {
  212. tJavaTextEncodingFlavor = new DataFlavor
  213. ("application/x-java-text-encoding;class=\"[B\"");
  214. } catch (ClassNotFoundException cannotHappen) {
  215. }
  216. javaTextEncodingFlavor = tJavaTextEncodingFlavor;
  217. Map tempMap = new HashMap(17);
  218. tempMap.put("sgml", Boolean.TRUE);
  219. tempMap.put("xml", Boolean.TRUE);
  220. tempMap.put("html", Boolean.TRUE);
  221. tempMap.put("enriched", Boolean.TRUE);
  222. tempMap.put("richtext", Boolean.TRUE);
  223. tempMap.put("uri-list", Boolean.TRUE);
  224. tempMap.put("directory", Boolean.TRUE);
  225. tempMap.put("css", Boolean.TRUE);
  226. tempMap.put("calendar", Boolean.TRUE);
  227. tempMap.put("plain", Boolean.TRUE);
  228. tempMap.put("rtf", Boolean.FALSE);
  229. tempMap.put("tab-separated-values", Boolean.FALSE);
  230. tempMap.put("t140", Boolean.FALSE);
  231. tempMap.put("rfc822-headers", Boolean.FALSE);
  232. tempMap.put("parityfec", Boolean.FALSE);
  233. textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap);
  234. }
  235. /**
  236. * The accessor method for the singleton DataTransferer instance. Note
  237. * that in a headless environment, there may be no DataTransferer instance;
  238. * instead, null will be returned.
  239. */
  240. public static synchronized DataTransferer getInstance() {
  241. return ((ComponentFactory) Toolkit.getDefaultToolkit()).getDataTransferer();
  242. }
  243. /**
  244. * Converts an arbitrary text encoding to its canonical name.
  245. */
  246. public static String canonicalName(String encoding) {
  247. if (encoding == null) {
  248. return null;
  249. }
  250. try {
  251. return Charset.forName(encoding).name();
  252. } catch (IllegalCharsetNameException icne) {
  253. return encoding;
  254. } catch (UnsupportedCharsetException uce) {
  255. return encoding;
  256. }
  257. }
  258. /**
  259. * If the specified flavor is a text flavor which supports the "charset"
  260. * parameter, then this method returns that parameter, or the default
  261. * charset if no such parameter was specified at construction. For non-
  262. * text DataFlavors, and for non-charset text flavors, this method returns
  263. * null.
  264. */
  265. public static String getTextCharset(DataFlavor flavor) {
  266. if (!isFlavorCharsetTextType(flavor)) {
  267. return null;
  268. }
  269. String encoding = flavor.getParameter("charset");
  270. return (encoding != null) ? encoding : getDefaultTextCharset();
  271. }
  272. /**
  273. * Returns the platform's default character encoding.
  274. */
  275. public static String getDefaultTextCharset() {
  276. if (defaultEncoding != null) {
  277. return defaultEncoding;
  278. }
  279. return defaultEncoding = Charset.defaultCharset().name();
  280. }
  281. /**
  282. * Tests only whether the flavor's MIME type supports the charset
  283. * parameter. Must only be called for flavors with a primary type of
  284. * "text".
  285. */
  286. public static boolean doesSubtypeSupportCharset(DataFlavor flavor) {
  287. if (dtLog.isLoggable(PlatformLogger.Level.FINE)) {
  288. if (!"text".equals(flavor.getPrimaryType())) {
  289. dtLog.fine("Assertion (\"text\".equals(flavor.getPrimaryType())) failed");
  290. }
  291. }
  292. String subType = flavor.getSubType();
  293. if (subType == null) {
  294. return false;
  295. }
  296. Object support = textMIMESubtypeCharsetSupport.get(subType);
  297. if (support != null) {
  298. return (support == Boolean.TRUE);
  299. }
  300. boolean ret_val = (flavor.getParameter("charset") != null);
  301. textMIMESubtypeCharsetSupport.put
  302. (subType, (ret_val) ? Boolean.TRUE : Boolean.FALSE);
  303. return ret_val;
  304. }
  305. public static boolean doesSubtypeSupportCharset(String subType,
  306. String charset)
  307. {
  308. Object support = textMIMESubtypeCharsetSupport.get(subType);
  309. if (support != null) {
  310. return (support == Boolean.TRUE);
  311. }
  312. boolean ret_val = (charset != null);
  313. textMIMESubtypeCharsetSupport.put
  314. (subType, (ret_val) ? Boolean.TRUE : Boolean.FALSE);
  315. return ret_val;
  316. }
  317. /**
  318. * Returns whether this flavor is a text type which supports the
  319. * 'charset' parameter.
  320. */
  321. public static boolean isFlavorCharsetTextType(DataFlavor flavor) {
  322. // Although stringFlavor doesn't actually support the charset
  323. // parameter (because its primary MIME type is not "text"), it should
  324. // be treated as though it does. stringFlavor is semantically
  325. // equivalent to "text/plain" data.
  326. if (DataFlavor.stringFlavor.equals(flavor)) {
  327. return true;
  328. }
  329. if (!"text".equals(flavor.getPrimaryType()) ||
  330. !doesSubtypeSupportCharset(flavor))
  331. {
  332. return false;
  333. }
  334. Class rep_class = flavor.getRepresentationClass();
  335. if (flavor.isRepresentationClassReader() ||
  336. String.class.equals(rep_class) ||
  337. flavor.isRepresentationClassCharBuffer() ||
  338. char[].class.equals(rep_class))
  339. {
  340. return true;
  341. }
  342. if (!(flavor.isRepresentationClassInputStream() ||
  343. flavor.isRepresentationClassByteBuffer() ||
  344. byte[].class.equals(rep_class))) {
  345. return false;
  346. }
  347. String charset = flavor.getParameter("charset");
  348. return (charset != null)
  349. ? DataTransferer.isEncodingSupported(charset)
  350. : true; // null equals default encoding which is always supported
  351. }
  352. /**
  353. * Returns whether this flavor is a text type which does not support the
  354. * 'charset' parameter.
  355. */
  356. public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) {
  357. if (!"text".equals(flavor.getPrimaryType()) ||
  358. doesSubtypeSupportCharset(flavor))
  359. {
  360. return false;
  361. }
  362. return (flavor.isRepresentationClassInputStream() ||
  363. flavor.isRepresentationClassByteBuffer() ||
  364. byte[].class.equals(flavor.getRepresentationClass()));
  365. }
  366. /**
  367. * Determines whether this JRE can both encode and decode text in the
  368. * specified encoding.
  369. */
  370. public static boolean isEncodingSupported(String encoding) {
  371. if (encoding == null) {
  372. return false;
  373. }
  374. try {
  375. return Charset.isSupported(encoding);
  376. } catch (IllegalCharsetNameException icne) {
  377. return false;
  378. }
  379. }
  380. /**
  381. * Returns {@code true} if the given type is a java.rmi.Remote.
  382. */
  383. public static boolean isRemote(Class<?> type) {
  384. return RMI.isRemote(type);
  385. }
  386. /**
  387. * Returns an Iterator which traverses a SortedSet of Strings which are
  388. * a total order of the standard character sets supported by the JRE. The
  389. * ordering follows the same principles as DataFlavor.selectBestTextFlavor.
  390. * So as to avoid loading all available character converters, optional,
  391. * non-standard, character sets are not included.
  392. */
  393. public static Set <String> standardEncodings() {
  394. return StandardEncodingsHolder.standardEncodings;
  395. }
  396. /**
  397. * Converts a FlavorMap to a FlavorTable.
  398. */
  399. public static FlavorTable adaptFlavorMap(final FlavorMap map) {
  400. if (map instanceof FlavorTable) {
  401. return (FlavorTable)map;
  402. }
  403. return new FlavorTable() {
  404. public Map getNativesForFlavors(DataFlavor[] flavors) {
  405. return map.getNativesForFlavors(flavors);
  406. }
  407. public Map getFlavorsForNatives(String[] natives) {
  408. return map.getFlavorsForNatives(natives);
  409. }
  410. public List getNativesForFlavor(DataFlavor flav) {
  411. Map natives =
  412. getNativesForFlavors(new DataFlavor[] { flav } );
  413. String nat = (String)natives.get(flav);
  414. if (nat != null) {
  415. List list = new ArrayList(1);
  416. list.add(nat);
  417. return list;
  418. } else {
  419. return Collections.EMPTY_LIST;
  420. }
  421. }
  422. public List getFlavorsForNative(String nat) {
  423. Map flavors =
  424. getFlavorsForNatives(new String[] { nat } );
  425. DataFlavor flavor = (DataFlavor)flavors.get(nat);
  426. if (flavor != null) {
  427. List list = new ArrayList(1);
  428. list.add(flavor);
  429. return list;
  430. } else {
  431. return Collections.EMPTY_LIST;
  432. }
  433. }
  434. };
  435. }
  436. /**
  437. * Returns the default Unicode encoding for the platform. The encoding
  438. * need not be canonical. This method is only used by the archaic function
  439. * DataFlavor.getTextPlainUnicodeFlavor().
  440. */
  441. public abstract String getDefaultUnicodeEncoding();
  442. /**
  443. * This method is called for text flavor mappings established while parsing
  444. * the flavormap.properties file. It stores the "eoln" and "terminators"
  445. * parameters which are not officially part of the MIME type. They are
  446. * MIME parameters specific to the flavormap.properties file format.
  447. */
  448. public void registerTextFlavorProperties(String nat, String charset,
  449. String eoln, String terminators) {
  450. Long format = getFormatForNativeAsLong(nat);
  451. textNatives.add(format);
  452. nativeCharsets.put(format, (charset != null && charset.length() != 0)
  453. ? charset : getDefaultTextCharset());
  454. if (eoln != null && eoln.length() != 0 && !eoln.equals("\n")) {
  455. nativeEOLNs.put(format, eoln);
  456. }
  457. if (terminators != null && terminators.length() != 0) {
  458. Integer iTerminators = Integer.valueOf(terminators);
  459. if (iTerminators.intValue() > 0) {
  460. nativeTerminators.put(format, iTerminators);
  461. }
  462. }
  463. }
  464. /**
  465. * Determines whether the native corresponding to the specified long format
  466. * was listed in the flavormap.properties file.
  467. */
  468. protected boolean isTextFormat(long format) {
  469. return textNatives.contains(Long.valueOf(format));
  470. }
  471. protected String getCharsetForTextFormat(Long lFormat) {
  472. return (String)nativeCharsets.get(lFormat);
  473. }
  474. /**
  475. * Specifies whether text imported from the native system in the specified
  476. * format is locale-dependent. If so, when decoding such text,
  477. * 'nativeCharsets' should be ignored, and instead, the Transferable should
  478. * be queried for its javaTextEncodingFlavor data for the correct encoding.
  479. */
  480. public abstract boolean isLocaleDependentTextFormat(long format);
  481. /**
  482. * Determines whether the DataFlavor corresponding to the specified long
  483. * format is DataFlavor.javaFileListFlavor.
  484. */
  485. public abstract boolean isFileFormat(long format);
  486. /**
  487. * Determines whether the DataFlavor corresponding to the specified long
  488. * format is DataFlavor.imageFlavor.
  489. */
  490. public abstract boolean isImageFormat(long format);
  491. /**
  492. * Determines whether the format is a URI list we can convert to
  493. * a DataFlavor.javaFileListFlavor.
  494. */
  495. protected boolean isURIListFormat(long format) {
  496. return false;
  497. }
  498. /**
  499. * Returns a Map whose keys are all of the possible formats into which the
  500. * Transferable's transfer data flavors can be translated. The value of
  501. * each key is the DataFlavor in which the Transferable's data should be
  502. * requested when converting to the format.
  503. * <p>
  504. * The map keys are sorted according to the native formats preference
  505. * order.
  506. */
  507. public SortedMap<Long,DataFlavor> getFormatsForTransferable(
  508. Transferable contents, FlavorTable map)
  509. {
  510. DataFlavor[] flavors = contents.getTransferDataFlavors();
  511. if (flavors == null) {
  512. return new TreeMap();
  513. }
  514. return getFormatsForFlavors(flavors, map);
  515. }
  516. /**
  517. * Returns a Map whose keys are all of the possible formats into which data
  518. * in the specified DataFlavor can be translated. The value of each key
  519. * is the DataFlavor in which a Transferable's data should be requested
  520. * when converting to the format.
  521. * <p>
  522. * The map keys are sorted according to the native formats preference
  523. * order.
  524. */
  525. public SortedMap getFormatsForFlavor(DataFlavor flavor, FlavorTable map) {
  526. return getFormatsForFlavors(new DataFlavor[] { flavor },
  527. map);
  528. }
  529. /**
  530. * Returns a Map whose keys are all of the possible formats into which data
  531. * in the specified DataFlavors can be translated. The value of each key
  532. * is the DataFlavor in which the Transferable's data should be requested
  533. * when converting to the format.
  534. * <p>
  535. * The map keys are sorted according to the native formats preference
  536. * order.
  537. *
  538. * @param flavors the data flavors
  539. * @param map the FlavorTable which contains mappings between
  540. * DataFlavors and data formats
  541. * @throws NullPointerException if flavors or map is <code>null</code>
  542. */
  543. public SortedMap <Long, DataFlavor> getFormatsForFlavors(
  544. DataFlavor[] flavors, FlavorTable map)
  545. {
  546. Map <Long,DataFlavor> formatMap =
  547. new HashMap <> (flavors.length);
  548. Map <Long,DataFlavor> textPlainMap =
  549. new HashMap <> (flavors.length);
  550. // Maps formats to indices that will be used to sort the formats
  551. // according to the preference order.
  552. // Larger index value corresponds to the more preferable format.
  553. Map indexMap = new HashMap(flavors.length);
  554. Map textPlainIndexMap = new HashMap(flavors.length);
  555. int currentIndex = 0;
  556. // Iterate backwards so that preferred DataFlavors are used over
  557. // other DataFlavors. (See javadoc for
  558. // Transferable.getTransferDataFlavors.)
  559. for (int i = flavors.length - 1; i >= 0; i--) {
  560. DataFlavor flavor = flavors[i];
  561. if (flavor == null) continue;
  562. // Don't explicitly test for String, since it is just a special
  563. // case of Serializable
  564. if (flavor.isFlavorTextType() ||
  565. flavor.isFlavorJavaFileListType() ||
  566. DataFlavor.imageFlavor.equals(flavor) ||
  567. flavor.isRepresentationClassSerializable() ||
  568. flavor.isRepresentationClassInputStream() ||
  569. flavor.isRepresentationClassRemote())
  570. {
  571. List natives = map.getNativesForFlavor(flavor);
  572. currentIndex += natives.size();
  573. for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
  574. Long lFormat =
  575. getFormatForNativeAsLong((String)iter.next());
  576. Integer index = Integer.valueOf(currentIndex--);
  577. formatMap.put(lFormat, flavor);
  578. indexMap.put(lFormat, index);
  579. // SystemFlavorMap.getNativesForFlavor will return
  580. // text/plain natives for all text/*. While this is good
  581. // for a single text/* flavor, we would prefer that
  582. // text/plain native data come from a text/plain flavor.
  583. if (("text".equals(flavor.getPrimaryType()) &&
  584. "plain".equals(flavor.getSubType())) ||
  585. flavor.equals(DataFlavor.stringFlavor))
  586. {
  587. textPlainMap.put(lFormat, flavor);
  588. textPlainIndexMap.put(lFormat, index);
  589. }
  590. }
  591. currentIndex += natives.size();
  592. }
  593. }
  594. formatMap.putAll(textPlainMap);
  595. indexMap.putAll(textPlainIndexMap);
  596. // Sort the map keys according to the formats preference order.
  597. Comparator comparator =
  598. new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
  599. SortedMap sortedMap = new TreeMap(comparator);
  600. sortedMap.putAll(formatMap);
  601. return sortedMap;
  602. }
  603. /**
  604. * Reduces the Map output for the root function to an array of the
  605. * Map's keys.
  606. */
  607. public long[] getFormatsForTransferableAsArray(Transferable contents,
  608. FlavorTable map) {
  609. return keysToLongArray(getFormatsForTransferable(contents, map));
  610. }
  611. public long[] getFormatsForFlavorAsArray(DataFlavor flavor,
  612. FlavorTable map) {
  613. return keysToLongArray(getFormatsForFlavor(flavor, map));
  614. }
  615. public long[] getFormatsForFlavorsAsArray(DataFlavor[] flavors,
  616. FlavorTable map) {
  617. return keysToLongArray(getFormatsForFlavors(flavors, map));
  618. }
  619. /**
  620. * Returns a Map whose keys are all of the possible DataFlavors into which
  621. * data in the specified format can be translated. The value of each key
  622. * is the format in which the Clipboard or dropped data should be requested
  623. * when converting to the DataFlavor.
  624. */
  625. public Map getFlavorsForFormat(long format, FlavorTable map) {
  626. return getFlavorsForFormats(new long[] { format }, map);
  627. }
  628. /**
  629. * Returns a Map whose keys are all of the possible DataFlavors into which
  630. * data in the specified formats can be translated. The value of each key
  631. * is the format in which the Clipboard or dropped data should be requested
  632. * when converting to the DataFlavor.
  633. */
  634. public Map getFlavorsForFormats(long[] formats, FlavorTable map) {
  635. Map flavorMap = new HashMap(formats.length);
  636. Set mappingSet = new HashSet(formats.length);
  637. Set flavorSet = new HashSet(formats.length);
  638. // First step: build flavorSet, mappingSet and initial flavorMap
  639. // flavorSet - the set of all the DataFlavors into which
  640. // data in the specified formats can be translated;
  641. // mappingSet - the set of all the mappings from the specified formats
  642. // into any DataFlavor;
  643. // flavorMap - after this step, this map maps each of the DataFlavors
  644. // from flavorSet to any of the specified formats.
  645. for (int i = 0; i < formats.length; i++) {
  646. long format = formats[i];
  647. String nat = getNativeForFormat(format);
  648. List flavors = map.getFlavorsForNative(nat);
  649. for (Iterator iter = flavors.iterator(); iter.hasNext(); ) {
  650. DataFlavor flavor = (DataFlavor)iter.next();
  651. // Don't explicitly test for String, since it is just a special
  652. // case of Serializable
  653. if (flavor.isFlavorTextType() ||
  654. flavor.isFlavorJavaFileListType() ||
  655. DataFlavor.imageFlavor.equals(flavor) ||
  656. flavor.isRepresentationClassSerializable() ||
  657. flavor.isRepresentationClassInputStream() ||
  658. flavor.isRepresentationClassRemote())
  659. {
  660. Long lFormat = Long.valueOf(format);
  661. Object mapping =
  662. DataTransferer.createMapping(lFormat, flavor);
  663. flavorMap.put(flavor, lFormat);
  664. mappingSet.add(mapping);
  665. flavorSet.add(flavor);
  666. }
  667. }
  668. }
  669. // Second step: for each DataFlavor try to figure out which of the
  670. // specified formats is the best to translate to this flavor.
  671. // Then map each flavor to the best format.
  672. // For the given flavor, FlavorTable indicates which native will
  673. // best reflect data in the specified flavor to the underlying native
  674. // platform. We assume that this native is the best to translate
  675. // to this flavor.
  676. // Note: FlavorTable allows one-way mappings, so we can occasionally
  677. // map a flavor to the format for which the corresponding
  678. // format-to-flavor mapping doesn't exist. For this reason we have built
  679. // a mappingSet of all format-to-flavor mappings for the specified formats
  680. // and check if the format-to-flavor mapping exists for the
  681. // (flavor,format) pair being added.
  682. for (Iterator flavorIter = flavorSet.iterator();
  683. flavorIter.hasNext(); ) {
  684. DataFlavor flavor = (DataFlavor)flavorIter.next();
  685. List natives = map.getNativesForFlavor(flavor);
  686. for (Iterator nativeIter = natives.iterator();
  687. nativeIter.hasNext(); ) {
  688. Long lFormat =
  689. getFormatForNativeAsLong((String)nativeIter.next());
  690. Object mapping = DataTransferer.createMapping(lFormat, flavor);
  691. if (mappingSet.contains(mapping)) {
  692. flavorMap.put(flavor, lFormat);
  693. break;
  694. }
  695. }
  696. }
  697. return flavorMap;
  698. }
  699. /**
  700. * Returns a Set of all DataFlavors for which
  701. * 1) a mapping from at least one of the specified formats exists in the
  702. * specified map and
  703. * 2) the data translation for this mapping can be performed by the data
  704. * transfer subsystem.
  705. *
  706. * @param formats the data formats
  707. * @param map the FlavorTable which contains mappings between
  708. * DataFlavors and data formats
  709. * @throws NullPointerException if formats or map is <code>null</code>
  710. */
  711. public Set getFlavorsForFormatsAsSet(long[] formats, FlavorTable map) {
  712. Set flavorSet = new HashSet(formats.length);
  713. for (int i = 0; i < formats.length; i++) {
  714. String nat = getNativeForFormat(formats[i]);
  715. List flavors = map.getFlavorsForNative(nat);
  716. for (Iterator iter = flavors.iterator(); iter.hasNext(); ) {
  717. DataFlavor flavor = (DataFlavor)iter.next();
  718. // Don't explicitly test for String, since it is just a special
  719. // case of Serializable
  720. if (flavor.isFlavorTextType() ||
  721. flavor.isFlavorJavaFileListType() ||
  722. DataFlavor.imageFlavor.equals(flavor) ||
  723. flavor.isRepresentationClassSerializable() ||
  724. flavor.isRepresentationClassInputStream() ||
  725. flavor.isRepresentationClassRemote())
  726. {
  727. flavorSet.add(flavor);
  728. }
  729. }
  730. }
  731. return flavorSet;
  732. }
  733. /**
  734. * Returns an array of all DataFlavors for which
  735. * 1) a mapping from the specified format exists in the specified map and
  736. * 2) the data translation for this mapping can be performed by the data
  737. * transfer subsystem.
  738. * The array will be sorted according to a
  739. * <code>DataFlavorComparator</code> created with the specified
  740. * map as an argument.
  741. *
  742. * @param format the data format
  743. * @param map the FlavorTable which contains mappings between
  744. * DataFlavors and data formats
  745. * @throws NullPointerException if map is <code>null</code>
  746. */
  747. public DataFlavor[] getFlavorsForFormatAsArray(long format,
  748. FlavorTable map) {
  749. return getFlavorsForFormatsAsArray(new long[] { format }, map);
  750. }
  751. /**
  752. * Returns an array of all DataFlavors for which
  753. * 1) a mapping from at least one of the specified formats exists in the
  754. * specified map and
  755. * 2) the data translation for this mapping can be performed by the data
  756. * transfer subsystem.
  757. * The array will be sorted according to a
  758. * <code>DataFlavorComparator</code> created with the specified
  759. * map as an argument.
  760. *
  761. * @param formats the data formats
  762. * @param map the FlavorTable which contains mappings between
  763. * DataFlavors and data formats
  764. * @throws NullPointerException if formats or map is <code>null</code>
  765. */
  766. public DataFlavor[] getFlavorsForFormatsAsArray(long[] formats,
  767. FlavorTable map) {
  768. // getFlavorsForFormatsAsSet() is less expensive than
  769. // getFlavorsForFormats().
  770. return setToSortedDataFlavorArray(getFlavorsForFormatsAsSet(formats, map));
  771. }
  772. /**
  773. * Returns an object that represents a mapping between the specified
  774. * key and value. <tt>null</tt> values and the <tt>null</tt> keys are
  775. * permitted. The internal representation of the mapping object is
  776. * irrelevant. The only requrement is that the two mapping objects are equal
  777. * if and only if their keys are equal and their values are equal.
  778. * More formally, the two mapping objects are equal if and only if
  779. * <tt>(value1 == null ? value2 == null : value1.equals(value2))
  780. * && (key1 == null ? key2 == null : key1.equals(key2))</tt>.
  781. */
  782. private static Object createMapping(Object key, Object value) {
  783. // NOTE: Should be updated to use AbstractMap.SimpleEntry as
  784. // soon as it is made public.
  785. return Arrays.asList(new Object[] { key, value });
  786. }
  787. /**
  788. * Looks-up or registers the String native with the native data transfer
  789. * system and returns a long format corresponding to that native.
  790. */
  791. protected abstract Long getFormatForNativeAsLong(String str);
  792. /**
  793. * Looks-up the String native corresponding to the specified long format in
  794. * the native data transfer system.
  795. */
  796. protected abstract String getNativeForFormat(long format);
  797. /* Contains common code for finding the best charset for
  798. * clipboard string encoding/decoding, basing on clipboard
  799. * format and localeTransferable(on decoding, if available)
  800. */
  801. private String getBestCharsetForTextFormat(Long lFormat,
  802. Transferable localeTransferable) throws IOException
  803. {
  804. String charset = null;
  805. if (localeTransferable != null &&
  806. isLocaleDependentTextFormat(lFormat) &&
  807. localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor))
  808. {
  809. try {
  810. charset = new String(
  811. (byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),
  812. "UTF-8"
  813. );
  814. } catch (UnsupportedFlavorException cannotHappen) {
  815. }
  816. } else {
  817. charset = getCharsetForTextFormat(lFormat);
  818. }
  819. if (charset == null) {
  820. // Only happens when we have a custom text type.
  821. charset = getDefaultTextCharset();
  822. }
  823. return charset;
  824. }
  825. /**
  826. * Translation function for converting string into
  827. * a byte array. Search-and-replace EOLN. Encode into the
  828. * target format. Append terminating NUL bytes.
  829. *
  830. * Java to Native string conversion
  831. */
  832. private byte[] translateTransferableString(String str,
  833. long format) throws IOException
  834. {
  835. Long lFormat = Long.valueOf(format);
  836. String charset = getBestCharsetForTextFormat(lFormat, null);
  837. // Search and replace EOLN. Note that if EOLN is "\n", then we
  838. // never added an entry to nativeEOLNs anyway, so we'll skip this
  839. // code altogether.
  840. // windows: "abc\nde"->"abc\r\nde"
  841. String eoln = (String)nativeEOLNs.get(lFormat);
  842. if (eoln != null) {
  843. int length = str.length();
  844. StringBuffer buffer =
  845. new StringBuffer(length * 2); // 2 is a heuristic
  846. for (int i = 0; i < length; i++) {
  847. // Fix for 4914613 - skip native EOLN
  848. if (str.startsWith(eoln, i)) {
  849. buffer.append(eoln);
  850. i += eoln.length() - 1;
  851. continue;
  852. }
  853. char c = str.charAt(i);
  854. if (c == '\n') {
  855. buffer.append(eoln);
  856. } else {
  857. buffer.append(c);
  858. }
  859. }
  860. str = buffer.toString();
  861. }
  862. // Encode text in target format.
  863. byte[] bytes = str.getBytes(charset);
  864. // Append terminating NUL bytes. Note that if terminators is 0,
  865. // the we never added an entry to nativeTerminators anyway, so
  866. // we'll skip code altogether.
  867. // "abcde" -> "abcde\0"
  868. Integer terminators = (Integer)nativeTerminators.get(lFormat);
  869. if (terminators != null) {
  870. int numTerminators = terminators.intValue();
  871. byte[] terminatedBytes =
  872. new byte[bytes.length + numTerminators];
  873. System.arraycopy(bytes, 0, terminatedBytes, 0, bytes.length);
  874. for (int i = bytes.length; i < terminatedBytes.length; i++) {
  875. terminatedBytes[i] = 0x0;
  876. }
  877. bytes = terminatedBytes;
  878. }
  879. return bytes;
  880. }
  881. /**
  882. * Translating either a byte array or an InputStream into an String.
  883. * Strip terminators and search-and-replace EOLN.
  884. *
  885. * Native to Java string conversion
  886. */
  887. private String translateBytesToString(byte[] bytes, long format,
  888. Transferable localeTransferable)
  889. throws IOException
  890. {
  891. Long lFormat = Long.valueOf(format);
  892. String charset = getBestCharsetForTextFormat(lFormat, localeTransferable);
  893. // Locate terminating NUL bytes. Note that if terminators is 0,
  894. // the we never added an entry to nativeTerminators anyway, so
  895. // we'll skip code altogether.
  896. // In other words: we are doing char alignment here basing on suggestion
  897. // that count of zero-'terminators' is a number of bytes in one symbol
  898. // for selected charset (clipboard format). It is not complitly true for
  899. // multibyte coding like UTF-8, but helps understand the procedure.
  900. // "abcde\0" -> "abcde"
  901. String eoln = (String)nativeEOLNs.get(lFormat);
  902. Integer terminators = (Integer)nativeTerminators.get(lFormat);
  903. int count;
  904. if (terminators != null) {
  905. int numTerminators = terminators.intValue();
  906. search:
  907. for (count = 0; count < (bytes.length - numTerminators + 1); count += numTerminators) {
  908. for (int i = count; i < count + numTerminators; i++) {
  909. if (bytes[i] != 0x0) {
  910. continue search;
  911. }
  912. }
  913. // found terminators
  914. break search;
  915. }
  916. } else {
  917. count = bytes.length;
  918. }
  919. // Decode text to chars. Don't include any terminators.
  920. String converted = new String(bytes, 0, count, charset);
  921. // Search and replace EOLN. Note that if EOLN is "\n", then we
  922. // never added an entry to nativeEOLNs anyway, so we'll skip this
  923. // code altogether.
  924. // Count of NUL-terminators and EOLN coding are platform-specific and
  925. // loaded from flavormap.properties file
  926. // windows: "abc\r\nde" -> "abc\nde"
  927. if (eoln != null) {
  928. /* Fix for 4463560: replace EOLNs symbol-by-symbol instead
  929. * of using buf.replace()
  930. */
  931. char[] buf = converted.toCharArray();
  932. char[] eoln_arr = eoln.toCharArray();
  933. converted = null;
  934. int j = 0;
  935. boolean match;
  936. for (int i = 0; i < buf.length; ) {
  937. // Catch last few bytes
  938. if (i + eoln_arr.length > buf.length) {
  939. buf[j++] = buf[i++];
  940. continue;
  941. }
  942. match = true;
  943. for (int k = 0, l = i; k < eoln_arr.length; k++, l++) {
  944. if (eoln_arr[k] != buf[l]) {
  945. match = false;
  946. break;
  947. }
  948. }
  949. if (match) {
  950. buf[j++] = '\n';
  951. i += eoln_arr.length;
  952. } else {
  953. buf[j++] = buf[i++];
  954. }
  955. }
  956. converted = new String(buf, 0, j);
  957. }
  958. return converted;
  959. }
  960. /**
  961. * Primary translation function for translating a Transferable into
  962. * a byte array, given a source DataFlavor and target format.
  963. */
  964. public byte[] translateTransferable(Transferable contents,
  965. DataFlavor flavor,
  966. long format) throws IOException
  967. {
  968. // Obtain the transfer data in the source DataFlavor.
  969. //
  970. // Note that we special case DataFlavor.plainTextFlavor because
  971. // StringSelection supports this flavor incorrectly -- instead of
  972. // returning an InputStream as the DataFlavor representation class
  973. // states, it returns a Reader. Instead of using this broken
  974. // functionality, we request the data in stringFlavor (the other
  975. // DataFlavor which StringSelection supports) and use the String
  976. // translator.
  977. Object obj;
  978. boolean stringSelectionHack;
  979. try {
  980. obj = contents.getTransferData(flavor);
  981. if (obj == null) {
  982. return null;
  983. }
  984. if (flavor.equals(DataFlavor.plainTextFlavor) &&
  985. !(obj instanceof InputStream))
  986. {
  987. obj = contents.getTransferData(DataFlavor.stringFlavor);
  988. if (obj == null) {
  989. return null;
  990. }
  991. stringSelectionHack = true;
  992. } else {
  993. stringSelectionHack = false;
  994. }
  995. } catch (UnsupportedFlavorException e) {
  996. throw new IOException(e.getMessage());
  997. }
  998. // Source data is a String. Search-and-replace EOLN. Encode into the
  999. // target format. Append terminating NUL bytes.
  1000. if (stringSelectionHack ||
  1001. (String.class.equals(flavor.getRepresentationClass()) &&
  1002. isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1003. String str = removeSuspectedData(flavor, contents, (String)obj);
  1004. return translateTransferableString(
  1005. str,
  1006. format);
  1007. // Source data is a Reader. Convert to a String and recur. In the
  1008. // future, we may want to rewrite this so that we encode on demand.
  1009. } else if (flavor.isRepresentationClassReader()) {
  1010. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1011. throw new IOException
  1012. ("cannot transfer non-text data as Reader");
  1013. }
  1014. StringBuffer buf = new StringBuffer();
  1015. try (Reader r = (Reader)obj) {
  1016. int c;
  1017. while ((c = r.read()) != -1) {
  1018. buf.append((char)c);
  1019. }
  1020. }
  1021. return translateTransferableString(
  1022. buf.toString(),
  1023. format);
  1024. // Source data is a CharBuffer. Convert to a String and recur.
  1025. } else if (flavor.isRepresentationClassCharBuffer()) {
  1026. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1027. throw new IOException
  1028. ("cannot transfer non-text data as CharBuffer");
  1029. }
  1030. CharBuffer buffer = (CharBuffer)obj;
  1031. int size = buffer.remaining();
  1032. char[] chars = new char[size];
  1033. buffer.get(chars, 0, size);
  1034. return translateTransferableString(
  1035. new String(chars),
  1036. format);
  1037. // Source data is a char array. Convert to a String and recur.
  1038. } else if (char[].class.equals(flavor.getRepresentationClass())) {
  1039. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1040. throw new IOException
  1041. ("cannot transfer non-text data as char array");
  1042. }
  1043. return translateTransferableString(
  1044. new String((char[])obj),
  1045. format);
  1046. // Source data is a ByteBuffer. For arbitrary flavors, simply return
  1047. // the array. For text flavors, decode back to a String and recur to
  1048. // reencode according to the requested format.
  1049. } else if (flavor.isRepresentationClassByteBuffer()) {
  1050. ByteBuffer buffer = (ByteBuffer)obj;
  1051. int size = buffer.remaining();
  1052. byte[] bytes = new byte[size];
  1053. buffer.get(bytes, 0, size);
  1054. if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
  1055. String sourceEncoding = DataTransferer.getTextCharset(flavor);
  1056. return translateTransferableString(
  1057. new String(bytes, sourceEncoding),
  1058. format);
  1059. } else {
  1060. return bytes;
  1061. }
  1062. // Source data is a byte array. For arbitrary flavors, simply return
  1063. // the array. For text flavors, decode back to a String and recur to
  1064. // reencode according to the requested format.
  1065. } else if (byte[].class.equals(flavor.getRepresentationClass())) {
  1066. byte[] bytes = (byte[])obj;
  1067. if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
  1068. String sourceEncoding = DataTransferer.getTextCharset(flavor);
  1069. return translateTransferableString(
  1070. new String(bytes, sourceEncoding),
  1071. format);
  1072. } else {
  1073. return bytes;
  1074. }
  1075. // Source data is Image
  1076. } else if (DataFlavor.imageFlavor.equals(flavor)) {
  1077. if (!isImageFormat(format)) {
  1078. throw new IOException("Data translation failed: " +
  1079. "not an image format");
  1080. }
  1081. Image image = (Image)obj;
  1082. byte[] bytes = imageToPlatformBytes(image, format);
  1083. if (bytes == null) {
  1084. throw new IOException("Data translation failed: " +
  1085. "cannot convert java image to native format");
  1086. }
  1087. return bytes;
  1088. }
  1089. byte[] theByteArray = null;
  1090. // Target data is a file list. Source data must be a
  1091. // java.util.List which contains java.io.File or String instances.
  1092. if (isFileFormat(format)) {
  1093. if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
  1094. throw new IOException("data translation failed");
  1095. }
  1096. final List list = (List)obj;
  1097. final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
  1098. final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
  1099. try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) {
  1100. theByteArray = bos.toByteArray();
  1101. }
  1102. // Target data is a URI list. Source data must be a
  1103. // java.util.List which contains java.io.File or String instances.
  1104. } else if (isURIListFormat(format)) {
  1105. if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
  1106. throw new IOException("data translation failed");
  1107. }
  1108. String nat = getNativeForFormat(format);
  1109. String targetCharset = null;
  1110. if (nat != null) {
  1111. try {
  1112. targetCharset = new DataFlavor(nat).getParameter("charset");
  1113. } catch (ClassNotFoundException cnfe) {
  1114. throw new IOException(cnfe);
  1115. }
  1116. }
  1117. if (targetCharset == null) {
  1118. targetCharset = "UTF-8";
  1119. }
  1120. final List list = (List)obj;
  1121. final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
  1122. final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
  1123. final ArrayList<String> uriList = new ArrayList<String>(fileList.size());
  1124. for (String fileObject : fileList) {
  1125. final URI uri = new File(fileObject).toURI();
  1126. // Some implementations are fussy about the number of slashes (file:///path/to/file is best)
  1127. try {
  1128. uriList.add(new URI(uri.getScheme(), "", uri.getPath(), uri.getFragment()).toString());
  1129. } catch (URISyntaxException uriSyntaxException) {
  1130. throw new IOException(uriSyntaxException);
  1131. }
  1132. }
  1133. byte[] eoln = "\r\n".getBytes(targetCharset);
  1134. try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
  1135. for (int i = 0; i < uriList.size(); i++) {
  1136. byte[] bytes = uriList.get(i).getBytes(targetCharset);
  1137. bos.write(bytes, 0, bytes.length);
  1138. bos.write(eoln, 0, eoln.length);
  1139. }
  1140. theByteArray = bos.toByteArray();
  1141. }
  1142. // Source data is an InputStream. For arbitrary flavors, just grab th…

Large files files are truncated, but you can click here to view the full file