PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/psandoz/lambda-jdk-pipeline-patches
Java | 3099 lines | 1953 code | 392 blank | 754 comment | 391 complexity | ae029abb461d6acef124b5117f94d6c1 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0

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

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

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