PageRenderTime 75ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/infinitekind/openjdk7u-jdk
Java | 3090 lines | 1944 code | 392 blank | 754 comment | 389 complexity | 47e806af89d2a7c61fd4c6bc2e7a83a5 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 getFormatsForTransferable(Transferable contents,
  577. FlavorTable map) {
  578. DataFlavor[] flavors = contents.getTransferDataFlavors();
  579. if (flavors == null) {
  580. return new TreeMap();
  581. }
  582. return getFormatsForFlavors(flavors, map);
  583. }
  584. /**
  585. * Returns a Map whose keys are all of the possible formats into which data
  586. * in the specified DataFlavor can be translated. The value of each key
  587. * is the DataFlavor in which a Transferable's data should be requested
  588. * when converting to the format.
  589. * <p>
  590. * The map keys are sorted according to the native formats preference
  591. * order.
  592. */
  593. public SortedMap getFormatsForFlavor(DataFlavor flavor, FlavorTable map) {
  594. return getFormatsForFlavors(new DataFlavor[] { flavor },
  595. map);
  596. }
  597. /**
  598. * Returns a Map whose keys are all of the possible formats into which data
  599. * in the specified DataFlavors can be translated. The value of each key
  600. * is the DataFlavor in which the Transferable's data should be requested
  601. * when converting to the format.
  602. * <p>
  603. * The map keys are sorted according to the native formats preference
  604. * order.
  605. *
  606. * @param flavors the data flavors
  607. * @param map the FlavorTable which contains mappings between
  608. * DataFlavors and data formats
  609. * @throws NullPointerException if flavors or map is <code>null</code>
  610. */
  611. public SortedMap getFormatsForFlavors(DataFlavor[] flavors, FlavorTable map) {
  612. Map formatMap = new HashMap(flavors.length);
  613. Map textPlainMap = new HashMap(flavors.length);
  614. // Maps formats to indices that will be used to sort the formats
  615. // according to the preference order.
  616. // Larger index value corresponds to the more preferable format.
  617. Map indexMap = new HashMap(flavors.length);
  618. Map textPlainIndexMap = new HashMap(flavors.length);
  619. int currentIndex = 0;
  620. // Iterate backwards so that preferred DataFlavors are used over
  621. // other DataFlavors. (See javadoc for
  622. // Transferable.getTransferDataFlavors.)
  623. for (int i = flavors.length - 1; i >= 0; i--) {
  624. DataFlavor flavor = flavors[i];
  625. if (flavor == null) continue;
  626. // Don't explicitly test for String, since it is just a special
  627. // case of Serializable
  628. if (flavor.isFlavorTextType() ||
  629. flavor.isFlavorJavaFileListType() ||
  630. DataFlavor.imageFlavor.equals(flavor) ||
  631. flavor.isRepresentationClassSerializable() ||
  632. flavor.isRepresentationClassInputStream() ||
  633. flavor.isRepresentationClassRemote())
  634. {
  635. List natives = map.getNativesForFlavor(flavor);
  636. currentIndex += natives.size();
  637. for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
  638. Long lFormat =
  639. getFormatForNativeAsLong((String)iter.next());
  640. Integer index = Integer.valueOf(currentIndex--);
  641. formatMap.put(lFormat, flavor);
  642. indexMap.put(lFormat, index);
  643. // SystemFlavorMap.getNativesForFlavor will return
  644. // text/plain natives for all text/*. While this is good
  645. // for a single text/* flavor, we would prefer that
  646. // text/plain native data come from a text/plain flavor.
  647. if (("text".equals(flavor.getPrimaryType()) &&
  648. "plain".equals(flavor.getSubType())) ||
  649. flavor.equals(DataFlavor.stringFlavor))
  650. {
  651. textPlainMap.put(lFormat, flavor);
  652. textPlainIndexMap.put(lFormat, index);
  653. }
  654. }
  655. currentIndex += natives.size();
  656. }
  657. }
  658. formatMap.putAll(textPlainMap);
  659. indexMap.putAll(textPlainIndexMap);
  660. // Sort the map keys according to the formats preference order.
  661. Comparator comparator =
  662. new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
  663. SortedMap sortedMap = new TreeMap(comparator);
  664. sortedMap.putAll(formatMap);
  665. return sortedMap;
  666. }
  667. /**
  668. * Reduces the Map output for the root function to an array of the
  669. * Map's keys.
  670. */
  671. public long[] getFormatsForTransferableAsArray(Transferable contents,
  672. FlavorTable map) {
  673. return keysToLongArray(getFormatsForTransferable(contents, map));
  674. }
  675. public long[] getFormatsForFlavorAsArray(DataFlavor flavor,
  676. FlavorTable map) {
  677. return keysToLongArray(getFormatsForFlavor(flavor, map));
  678. }
  679. public long[] getFormatsForFlavorsAsArray(DataFlavor[] flavors,
  680. FlavorTable map) {
  681. return keysToLongArray(getFormatsForFlavors(flavors, map));
  682. }
  683. /**
  684. * Returns a Map whose keys are all of the possible DataFlavors into which
  685. * data in the specified format can be translated. The value of each key
  686. * is the format in which the Clipboard or dropped data should be requested
  687. * when converting to the DataFlavor.
  688. */
  689. public Map getFlavorsForFormat(long format, FlavorTable map) {
  690. return getFlavorsForFormats(new long[] { format }, map);
  691. }
  692. /**
  693. * Returns a Map whose keys are all of the possible DataFlavors into which
  694. * data in the specified formats can be translated. The value of each key
  695. * is the format in which the Clipboard or dropped data should be requested
  696. * when converting to the DataFlavor.
  697. */
  698. public Map getFlavorsForFormats(long[] formats, FlavorTable map) {
  699. Map flavorMap = new HashMap(formats.length);
  700. Set mappingSet = new HashSet(formats.length);
  701. Set flavorSet = new HashSet(formats.length);
  702. // First step: build flavorSet, mappingSet and initial flavorMap
  703. // flavorSet - the set of all the DataFlavors into which
  704. // data in the specified formats can be translated;
  705. // mappingSet - the set of all the mappings from the specified formats
  706. // into any DataFlavor;
  707. // flavorMap - after this step, this map maps each of the DataFlavors
  708. // from flavorSet to any of the specified formats.
  709. for (int i = 0; i < formats.length; i++) {
  710. long format = formats[i];
  711. String nat = getNativeForFormat(format);
  712. List flavors = map.getFlavorsForNative(nat);
  713. for (Iterator iter = flavors.iterator(); iter.hasNext(); ) {
  714. DataFlavor flavor = (DataFlavor)iter.next();
  715. // Don't explicitly test for String, since it is just a special
  716. // case of Serializable
  717. if (flavor.isFlavorTextType() ||
  718. flavor.isFlavorJavaFileListType() ||
  719. DataFlavor.imageFlavor.equals(flavor) ||
  720. flavor.isRepresentationClassSerializable() ||
  721. flavor.isRepresentationClassInputStream() ||
  722. flavor.isRepresentationClassRemote())
  723. {
  724. Long lFormat = Long.valueOf(format);
  725. Object mapping =
  726. DataTransferer.createMapping(lFormat, flavor);
  727. flavorMap.put(flavor, lFormat);
  728. mappingSet.add(mapping);
  729. flavorSet.add(flavor);
  730. }
  731. }
  732. }
  733. // Second step: for each DataFlavor try to figure out which of the
  734. // specified formats is the best to translate to this flavor.
  735. // Then map each flavor to the best format.
  736. // For the given flavor, FlavorTable indicates which native will
  737. // best reflect data in the specified flavor to the underlying native
  738. // platform. We assume that this native is the best to translate
  739. // to this flavor.
  740. // Note: FlavorTable allows one-way mappings, so we can occasionally
  741. // map a flavor to the format for which the corresponding
  742. // format-to-flavor mapping doesn't exist. For this reason we have built
  743. // a mappingSet of all format-to-flavor mappings for the specified formats
  744. // and check if the format-to-flavor mapping exists for the
  745. // (flavor,format) pair being added.
  746. for (Iterator flavorIter = flavorSet.iterator();
  747. flavorIter.hasNext(); ) {
  748. DataFlavor flavor = (DataFlavor)flavorIter.next();
  749. List natives = map.getNativesForFlavor(flavor);
  750. for (Iterator nativeIter = natives.iterator();
  751. nativeIter.hasNext(); ) {
  752. Long lFormat =
  753. getFormatForNativeAsLong((String)nativeIter.next());
  754. Object mapping = DataTransferer.createMapping(lFormat, flavor);
  755. if (mappingSet.contains(mapping)) {
  756. flavorMap.put(flavor, lFormat);
  757. break;
  758. }
  759. }
  760. }
  761. return flavorMap;
  762. }
  763. /**
  764. * Returns a Set of all DataFlavors for which
  765. * 1) a mapping from at least one of the specified formats exists in the
  766. * specified map and
  767. * 2) the data translation for this mapping can be performed by the data
  768. * transfer subsystem.
  769. *
  770. * @param formats the data formats
  771. * @param map the FlavorTable which contains mappings between
  772. * DataFlavors and data formats
  773. * @throws NullPointerException if formats or map is <code>null</code>
  774. */
  775. public Set getFlavorsForFormatsAsSet(long[] formats, FlavorTable map) {
  776. Set flavorSet = new HashSet(formats.length);
  777. for (int i = 0; i < formats.length; i++) {
  778. String nat = getNativeForFormat(formats[i]);
  779. List flavors = map.getFlavorsForNative(nat);
  780. for (Iterator iter = flavors.iterator(); iter.hasNext(); ) {
  781. DataFlavor flavor = (DataFlavor)iter.next();
  782. // Don't explicitly test for String, since it is just a special
  783. // case of Serializable
  784. if (flavor.isFlavorTextType() ||
  785. flavor.isFlavorJavaFileListType() ||
  786. DataFlavor.imageFlavor.equals(flavor) ||
  787. flavor.isRepresentationClassSerializable() ||
  788. flavor.isRepresentationClassInputStream() ||
  789. flavor.isRepresentationClassRemote())
  790. {
  791. flavorSet.add(flavor);
  792. }
  793. }
  794. }
  795. return flavorSet;
  796. }
  797. /**
  798. * Returns an array of all DataFlavors for which
  799. * 1) a mapping from the specified format exists in the specified map and
  800. * 2) the data translation for this mapping can be performed by the data
  801. * transfer subsystem.
  802. * The array will be sorted according to a
  803. * <code>DataFlavorComparator</code> created with the specified
  804. * map as an argument.
  805. *
  806. * @param format the data format
  807. * @param map the FlavorTable which contains mappings between
  808. * DataFlavors and data formats
  809. * @throws NullPointerException if map is <code>null</code>
  810. */
  811. public DataFlavor[] getFlavorsForFormatAsArray(long format,
  812. FlavorTable map) {
  813. return getFlavorsForFormatsAsArray(new long[] { format }, map);
  814. }
  815. /**
  816. * Returns an array of all DataFlavors for which
  817. * 1) a mapping from at least one of the specified formats exists in the
  818. * specified map and
  819. * 2) the data translation for this mapping can be performed by the data
  820. * transfer subsystem.
  821. * The array will be sorted according to a
  822. * <code>DataFlavorComparator</code> created with the specified
  823. * map as an argument.
  824. *
  825. * @param formats the data formats
  826. * @param map the FlavorTable which contains mappings between
  827. * DataFlavors and data formats
  828. * @throws NullPointerException if formats or map is <code>null</code>
  829. */
  830. public DataFlavor[] getFlavorsForFormatsAsArray(long[] formats,
  831. FlavorTable map) {
  832. // getFlavorsForFormatsAsSet() is less expensive than
  833. // getFlavorsForFormats().
  834. return setToSortedDataFlavorArray(getFlavorsForFormatsAsSet(formats, map));
  835. }
  836. /**
  837. * Returns an object that represents a mapping between the specified
  838. * key and value. <tt>null</tt> values and the <tt>null</tt> keys are
  839. * permitted. The internal representation of the mapping object is
  840. * irrelevant. The only requrement is that the two mapping objects are equal
  841. * if and only if their keys are equal and their values are equal.
  842. * More formally, the two mapping objects are equal if and only if
  843. * <tt>(value1 == null ? value2 == null : value1.equals(value2))
  844. * && (key1 == null ? key2 == null : key1.equals(key2))</tt>.
  845. */
  846. private static Object createMapping(Object key, Object value) {
  847. // NOTE: Should be updated to use AbstractMap.SimpleEntry as
  848. // soon as it is made public.
  849. return Arrays.asList(new Object[] { key, value });
  850. }
  851. /**
  852. * Looks-up or registers the String native with the native data transfer
  853. * system and returns a long format corresponding to that native.
  854. */
  855. protected abstract Long getFormatForNativeAsLong(String str);
  856. /**
  857. * Looks-up the String native corresponding to the specified long format in
  858. * the native data transfer system.
  859. */
  860. protected abstract String getNativeForFormat(long format);
  861. /* Contains common code for finding the best charset for
  862. * clipboard string encoding/decoding, basing on clipboard
  863. * format and localeTransferable(on decoding, if available)
  864. */
  865. private String getBestCharsetForTextFormat(Long lFormat,
  866. Transferable localeTransferable) throws IOException
  867. {
  868. String charset = null;
  869. if (localeTransferable != null &&
  870. isLocaleDependentTextFormat(lFormat) &&
  871. localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor))
  872. {
  873. try {
  874. charset = new String(
  875. (byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),
  876. "UTF-8"
  877. );
  878. } catch (UnsupportedFlavorException cannotHappen) {
  879. }
  880. } else {
  881. charset = getCharsetForTextFormat(lFormat);
  882. }
  883. if (charset == null) {
  884. // Only happens when we have a custom text type.
  885. charset = getDefaultTextCharset();
  886. }
  887. return charset;
  888. }
  889. /**
  890. * Translation function for converting string into
  891. * a byte array. Search-and-replace EOLN. Encode into the
  892. * target format. Append terminating NUL bytes.
  893. *
  894. * Java to Native string conversion
  895. */
  896. private byte[] translateTransferableString(String str,
  897. long format) throws IOException
  898. {
  899. Long lFormat = Long.valueOf(format);
  900. String charset = getBestCharsetForTextFormat(lFormat, null);
  901. // Search and replace EOLN. Note that if EOLN is "\n", then we
  902. // never added an entry to nativeEOLNs anyway, so we'll skip this
  903. // code altogether.
  904. // windows: "abc\nde"->"abc\r\nde"
  905. String eoln = (String)nativeEOLNs.get(lFormat);
  906. if (eoln != null) {
  907. int length = str.length();
  908. StringBuffer buffer =
  909. new StringBuffer(length * 2); // 2 is a heuristic
  910. for (int i = 0; i < length; i++) {
  911. // Fix for 4914613 - skip native EOLN
  912. if (str.startsWith(eoln, i)) {
  913. buffer.append(eoln);
  914. i += eoln.length() - 1;
  915. continue;
  916. }
  917. char c = str.charAt(i);
  918. if (c == '\n') {
  919. buffer.append(eoln);
  920. } else {
  921. buffer.append(c);
  922. }
  923. }
  924. str = buffer.toString();
  925. }
  926. // Encode text in target format.
  927. byte[] bytes = str.getBytes(charset);
  928. // Append terminating NUL bytes. Note that if terminators is 0,
  929. // the we never added an entry to nativeTerminators anyway, so
  930. // we'll skip code altogether.
  931. // "abcde" -> "abcde\0"
  932. Integer terminators = (Integer)nativeTerminators.get(lFormat);
  933. if (terminators != null) {
  934. int numTerminators = terminators.intValue();
  935. byte[] terminatedBytes =
  936. new byte[bytes.length + numTerminators];
  937. System.arraycopy(bytes, 0, terminatedBytes, 0, bytes.length);
  938. for (int i = bytes.length; i < terminatedBytes.length; i++) {
  939. terminatedBytes[i] = 0x0;
  940. }
  941. bytes = terminatedBytes;
  942. }
  943. return bytes;
  944. }
  945. /**
  946. * Translating either a byte array or an InputStream into an String.
  947. * Strip terminators and search-and-replace EOLN.
  948. *
  949. * Native to Java string conversion
  950. */
  951. private String translateBytesOrStreamToString(InputStream str, byte[] bytes,
  952. long format,
  953. Transferable localeTransferable)
  954. throws IOException
  955. {
  956. // A String holds all of its data in memory at one time, so
  957. // we can't avoid reading the entire InputStream at this point.
  958. if (bytes == null) {
  959. bytes = inputStreamToByteArray(str);
  960. }
  961. str.close();
  962. Long lFormat = Long.valueOf(format);
  963. String charset = getBestCharsetForTextFormat(lFormat, localeTransferable);
  964. // Locate terminating NUL bytes. Note that if terminators is 0,
  965. // the we never added an entry to nativeTerminators anyway, so
  966. // we'll skip code altogether.
  967. // In other words: we are doing char alignment here basing on suggestion
  968. // that count of zero-'terminators' is a number of bytes in one symbol
  969. // for selected charset (clipboard format). It is not complitly true for
  970. // multibyte coding like UTF-8, but helps understand the procedure.
  971. // "abcde\0" -> "abcde"
  972. String eoln = (String)nativeEOLNs.get(lFormat);
  973. Integer terminators = (Integer)nativeTerminators.get(lFormat);
  974. int count;
  975. if (terminators != null) {
  976. int numTerminators = terminators.intValue();
  977. search:
  978. for (count = 0; count < (bytes.length - numTerminators + 1); count += numTerminators) {
  979. for (int i = count; i < count + numTerminators; i++) {
  980. if (bytes[i] != 0x0) {
  981. continue search;
  982. }
  983. }
  984. // found terminators
  985. break search;
  986. }
  987. } else {
  988. count = bytes.length;
  989. }
  990. // Decode text to chars. Don't include any terminators.
  991. String converted = new String(bytes, 0, count, charset);
  992. // Search and replace EOLN. Note that if EOLN is "\n", then we
  993. // never added an entry to nativeEOLNs anyway, so we'll skip this
  994. // code altogether.
  995. // Count of NUL-terminators and EOLN coding are platform-specific and
  996. // loaded from flavormap.properties file
  997. // windows: "abc\r\nde" -> "abc\nde"
  998. if (eoln != null) {
  999. /* Fix for 4463560: replace EOLNs symbol-by-symbol instead
  1000. * of using buf.replace()
  1001. */
  1002. char[] buf = converted.toCharArray();
  1003. char[] eoln_arr = eoln.toCharArray();
  1004. converted = null;
  1005. int j = 0;
  1006. boolean match;
  1007. for (int i = 0; i < buf.length; ) {
  1008. // Catch last few bytes
  1009. if (i + eoln_arr.length > buf.length) {
  1010. buf[j++] = buf[i++];
  1011. continue;
  1012. }
  1013. match = true;
  1014. for (int k = 0, l = i; k < eoln_arr.length; k++, l++) {
  1015. if (eoln_arr[k] != buf[l]) {
  1016. match = false;
  1017. break;
  1018. }
  1019. }
  1020. if (match) {
  1021. buf[j++] = '\n';
  1022. i += eoln_arr.length;
  1023. } else {
  1024. buf[j++] = buf[i++];
  1025. }
  1026. }
  1027. converted = new String(buf, 0, j);
  1028. }
  1029. return converted;
  1030. }
  1031. /**
  1032. * Primary translation function for translating a Transferable into
  1033. * a byte array, given a source DataFlavor and target format.
  1034. */
  1035. public byte[] translateTransferable(Transferable contents,
  1036. DataFlavor flavor,
  1037. long format) throws IOException
  1038. {
  1039. // Obtain the transfer data in the source DataFlavor.
  1040. //
  1041. // Note that we special case DataFlavor.plainTextFlavor because
  1042. // StringSelection supports this flavor incorrectly -- instead of
  1043. // returning an InputStream as the DataFlavor representation class
  1044. // states, it returns a Reader. Instead of using this broken
  1045. // functionality, we request the data in stringFlavor (the other
  1046. // DataFlavor which StringSelection supports) and use the String
  1047. // translator.
  1048. Object obj;
  1049. boolean stringSelectionHack;
  1050. try {
  1051. obj = contents.getTransferData(flavor);
  1052. if (obj == null) {
  1053. return null;
  1054. }
  1055. if (flavor.equals(DataFlavor.plainTextFlavor) &&
  1056. !(obj instanceof InputStream))
  1057. {
  1058. obj = contents.getTransferData(DataFlavor.stringFlavor);
  1059. if (obj == null) {
  1060. return null;
  1061. }
  1062. stringSelectionHack = true;
  1063. } else {
  1064. stringSelectionHack = false;
  1065. }
  1066. } catch (UnsupportedFlavorException e) {
  1067. throw new IOException(e.getMessage());
  1068. }
  1069. // Source data is a String. Search-and-replace EOLN. Encode into the
  1070. // target format. Append terminating NUL bytes.
  1071. if (stringSelectionHack ||
  1072. (String.class.equals(flavor.getRepresentationClass()) &&
  1073. isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1074. String str = removeSuspectedData(flavor, contents, (String)obj);
  1075. return translateTransferableString(
  1076. str,
  1077. format);
  1078. // Source data is a Reader. Convert to a String and recur. In the
  1079. // future, we may want to rewrite this so that we encode on demand.
  1080. } else if (flavor.isRepresentationClassReader()) {
  1081. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1082. throw new IOException
  1083. ("cannot transfer non-text data as Reader");
  1084. }
  1085. Reader r = (Reader)obj;
  1086. StringBuffer buf = new StringBuffer();
  1087. int c;
  1088. while ((c = r.read()) != -1) {
  1089. buf.append((char)c);
  1090. }
  1091. r.close();
  1092. return translateTransferableString(
  1093. buf.toString(),
  1094. format);
  1095. // Source data is a CharBuffer. Convert to a String and recur.
  1096. } else if (flavor.isRepresentationClassCharBuffer()) {
  1097. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1098. throw new IOException
  1099. ("cannot transfer non-text data as CharBuffer");
  1100. }
  1101. CharBuffer buffer = (CharBuffer)obj;
  1102. int size = buffer.remaining();
  1103. char[] chars = new char[size];
  1104. buffer.get(chars, 0, size);
  1105. return translateTransferableString(
  1106. new String(chars),
  1107. format);
  1108. // Source data is a char array. Convert to a String and recur.
  1109. } else if (charArrayClass.equals(flavor.getRepresentationClass())) {
  1110. if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
  1111. throw new IOException
  1112. ("cannot transfer non-text data as char array");
  1113. }
  1114. return translateTransferableString(
  1115. new String((char[])obj),
  1116. format);
  1117. // Source data is a ByteBuffer. For arbitrary flavors, simply return
  1118. // the array. For text flavors, decode back to a String and recur to
  1119. // reencode according to the requested format.
  1120. } else if (flavor.isRepresentationClassByteBuffer()) {
  1121. ByteBuffer buffer = (ByteBuffer)obj;
  1122. int size = buffer.remaining();
  1123. byte[] bytes = new byte[size];
  1124. buffer.get(bytes, 0, size);
  1125. if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
  1126. String sourceEncoding = DataTransferer.getTextCharset(flavor);
  1127. return translateTransferableString(
  1128. new String(bytes, sourceEncoding),
  1129. format);
  1130. } else {
  1131. return bytes;
  1132. }
  1133. // Source data is a byte array. For arbitrary flavors, simply return
  1134. // the array. For text flavors, decode back to a String and recur to
  1135. // reencode according to the requested format.
  1136. } else if (byteArrayClass.equals(flavor.getRepresentationClass())) {
  1137. byte[] bytes = (byte[])obj;
  1138. if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
  1139. String sourceEncoding = DataTransferer.getTextCharset(flavor);
  1140. return translateTransferableString(
  1141. new String(bytes, sourceEncoding),
  1142. format);
  1143. } el

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