1299 lines · 53.6 KB · Java
RawDownload
/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt.datatransfer; import java.awt.Toolkit; import java.lang.ref.SoftReference; import java.io.BufferedReader;import java.io.File;import java.io.InputStreamReader;import java.io.IOException; import java.net.URL;import java.net.MalformedURLException; import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.WeakHashMap; import sun.awt.datatransfer.DataTransferer; /** * The SystemFlavorMap is a configurable map between "natives" (Strings), which * correspond to platform-specific data formats, and "flavors" (DataFlavors), * which correspond to platform-independent MIME types. This mapping is used * by the data transfer subsystem to transfer data between Java and native * applications, and between Java applications in separate VMs. * <p> * In the Sun reference implementation, the default SystemFlavorMap is * initialized by the file <code>jre/lib/flavormap.properties</code> and the * contents of the URL referenced by the AWT property * <code>AWT.DnD.flavorMapFileURL</code>. See <code>flavormap.properties</code> * for details. * * @since 1.2 */public final class SystemFlavorMap implements FlavorMap, FlavorTable {     /**     * Constant prefix used to tag Java types converted to native platform     * type.     */    private static String JavaMIME = "JAVA_DATAFLAVOR:";     /**     * System singleton which maps a thread's ClassLoader to a SystemFlavorMap.     */    private static final WeakHashMap flavorMaps = new WeakHashMap();     /**     * Copied from java.util.Properties.     */    private static final String keyValueSeparators = "=: \t\r\n\f";    private static final String strictKeyValueSeparators = "=:";    private static final String whiteSpaceChars = " \t\r\n\f";     /**     * The list of valid, decoded text flavor representation classes, in order     * from best to worst.     */    private static final String[] UNICODE_TEXT_CLASSES = {        "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\""    };     /**     * The list of valid, encoded text flavor representation classes, in order     * from best to worst.     */    private static final String[] ENCODED_TEXT_CLASSES = {        "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\""    };     /**     * A String representing text/plain MIME type.     */    private static final String TEXT_PLAIN_BASE_TYPE = "text/plain";     /**     * This constant is passed to flavorToNativeLookup() to indicate that a     * a native should be synthesized, stored, and returned by encoding the     * DataFlavor's MIME type in case if the DataFlavor is not found in     * 'flavorToNative' map.     */    private static final boolean SYNTHESIZE_IF_NOT_FOUND = true;     /**     * Maps native Strings to Lists of DataFlavors (or base type Strings for     * text DataFlavors).     * Do not use the field directly, use getNativeToFlavor() instead.     */    private Map nativeToFlavor = new HashMap();     /**     * Accessor to nativeToFlavor map.  Since we use lazy initialization we must     * use this accessor instead of direct access to the field which may not be     * initialized yet.  This method will initialize the field if needed.     *     * @return nativeToFlavor     */    private Map getNativeToFlavor() {        if (!isMapInitialized) {            initSystemFlavorMap();        }        return nativeToFlavor;    }     /**     * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of     * native Strings.     * Do not use the field directly, use getFlavorToNative() instead.     */    private Map flavorToNative = new HashMap();     /**     * Accessor to flavorToNative map.  Since we use lazy initialization we must     * use this accessor instead of direct access to the field which may not be     * initialized yet.  This method will initialize the field if needed.     *     * @return flavorToNative     */    private synchronized Map getFlavorToNative() {        if (!isMapInitialized) {            initSystemFlavorMap();        }        return flavorToNative;    }     /**     * Shows if the object has been initialized.     */    private boolean isMapInitialized = false;     /**     * Caches the result of getNativesForFlavor(). Maps DataFlavors to     * SoftReferences which reference Lists of String natives.     */    private Map getNativesForFlavorCache = new HashMap();     /**     * Caches the result getFlavorsForNative(). Maps String natives to     * SoftReferences which reference Lists of DataFlavors.     */    private Map getFlavorsForNativeCache = new HashMap();     /**     * Dynamic mapping generation used for text mappings should not be applied     * to the DataFlavors and String natives for which the mappings have been     * explicitly specified with setFlavorsForNative() or     * setNativesForFlavor(). This keeps all such keys.     */    private Set disabledMappingGenerationKeys = new HashSet();     /**     * Returns the default FlavorMap for this thread's ClassLoader.     */    public static FlavorMap getDefaultFlavorMap() {        ClassLoader contextClassLoader =            Thread.currentThread().getContextClassLoader();        if (contextClassLoader == null) {            contextClassLoader = ClassLoader.getSystemClassLoader();        }         FlavorMap fm;         synchronized(flavorMaps) {            fm = (FlavorMap)flavorMaps.get(contextClassLoader);            if (fm == null) {                fm = new SystemFlavorMap();                flavorMaps.put(contextClassLoader, fm);            }        }         return fm;    }     private SystemFlavorMap() {    }     /**     * Initializes a SystemFlavorMap by reading flavormap.properties and     * AWT.DnD.flavorMapFileURL.     * For thread-safety must be called under lock on this.     */    private void initSystemFlavorMap() {        if (isMapInitialized) {            return;        }         isMapInitialized = true;        BufferedReader flavormapDotProperties =            java.security.AccessController.doPrivileged(                new java.security.PrivilegedAction<BufferedReader>() {                    public BufferedReader run() {                        String fileName =                            System.getProperty("java.home") +                            File.separator +                            "lib" +                            File.separator +                            "flavormap.properties";                        try {                            return new BufferedReader                                (new InputStreamReader                                    (new File(fileName).toURI().toURL().openStream(), "ISO-8859-1"));                        } catch (MalformedURLException e) {                            System.err.println("MalformedURLException:" + e + " while loading default flavormap.properties file:" + fileName);                        } catch (IOException e) {                            System.err.println("IOException:" + e + " while loading default flavormap.properties file:" + fileName);                        }                        return null;                    }                });         BufferedReader flavormapURL =            java.security.AccessController.doPrivileged(                new java.security.PrivilegedAction<BufferedReader>() {                    public BufferedReader run() {                        String url = Toolkit.getProperty("AWT.DnD.flavorMapFileURL", null);                         if (url == null) {                            return null;                        }                         try {                            return new BufferedReader                                (new InputStreamReader                                    (new URL(url).openStream(), "ISO-8859-1"));                        } catch (MalformedURLException e) {                            System.err.println("MalformedURLException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url);                        } catch (IOException e) {                            System.err.println("IOException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url);                        }                        return null;                    }                });         if (flavormapDotProperties != null) {            try {                parseAndStoreReader(flavormapDotProperties);            } catch (IOException e) {                System.err.println("IOException:" + e + " while parsing default flavormap.properties file");            }        }         if (flavormapURL != null) {            try {                parseAndStoreReader(flavormapURL);            } catch (IOException e) {                System.err.println("IOException:" + e + " while parsing AWT.DnD.flavorMapFileURL");            }        }    }    /**     * Copied code from java.util.Properties. Parsing the data ourselves is the     * only way to handle duplicate keys and values.     */    private void parseAndStoreReader(BufferedReader in) throws IOException {        while (true) {            // Get next line            String line = in.readLine();            if (line == null) {                return;            }             if (line.length() > 0) {                // Continue lines that end in slashes if they are not comments                char firstChar = line.charAt(0);                if (firstChar != '#' && firstChar != '!') {                    while (continueLine(line)) {                        String nextLine = in.readLine();                        if (nextLine == null) {                            nextLine = "";                        }                        String loppedLine =                            line.substring(0, line.length() - 1);                        // Advance beyond whitespace on new line                        int startIndex = 0;                        for(; startIndex < nextLine.length(); startIndex++) {                            if (whiteSpaceChars.                                    indexOf(nextLine.charAt(startIndex)) == -1)                            {                                break;                            }                        }                        nextLine = nextLine.substring(startIndex,                                                      nextLine.length());                        line = loppedLine+nextLine;                    }                     // Find start of key                    int len = line.length();                    int keyStart = 0;                    for(; keyStart < len; keyStart++) {                        if(whiteSpaceChars.                               indexOf(line.charAt(keyStart)) == -1) {                            break;                        }                    }                     // Blank lines are ignored                    if (keyStart == len) {                        continue;                    }                     // Find separation between key and value                    int separatorIndex = keyStart;                    for(; separatorIndex < len; separatorIndex++) {                        char currentChar = line.charAt(separatorIndex);                        if (currentChar == '\\') {                            separatorIndex++;                        } else if (keyValueSeparators.                                       indexOf(currentChar) != -1) {                            break;                        }                    }                     // Skip over whitespace after key if any                    int valueIndex = separatorIndex;                    for (; valueIndex < len; valueIndex++) {                        if (whiteSpaceChars.                                indexOf(line.charAt(valueIndex)) == -1) {                            break;                        }                    }                     // Skip over one non whitespace key value separators if any                    if (valueIndex < len) {                        if (strictKeyValueSeparators.                                indexOf(line.charAt(valueIndex)) != -1) {                            valueIndex++;                        }                    }                     // Skip over white space after other separators if any                    while (valueIndex < len) {                        if (whiteSpaceChars.                                indexOf(line.charAt(valueIndex)) == -1) {                            break;                        }                        valueIndex++;                    }                     String key = line.substring(keyStart, separatorIndex);                    String value = (separatorIndex < len)                        ? line.substring(valueIndex, len)                        : "";                     // Convert then store key and value                    key = loadConvert(key);                    value = loadConvert(value);                     try {                        MimeType mime = new MimeType(value);                        if ("text".equals(mime.getPrimaryType())) {                            String charset = mime.getParameter("charset");                            if (DataTransferer.doesSubtypeSupportCharset                                    (mime.getSubType(), charset))                            {                                // We need to store the charset and eoln                                // parameters, if any, so that the                                // DataTransferer will have this information                                // for conversion into the native format.                                DataTransferer transferer =                                    DataTransferer.getInstance();                                if (transferer != null) {                                    transferer.registerTextFlavorProperties                                        (key, charset,                                         mime.getParameter("eoln"),                                         mime.getParameter("terminators"));                                }                            }                             // But don't store any of these parameters in the                            // DataFlavor itself for any text natives (even                            // non-charset ones). The SystemFlavorMap will                            // synthesize the appropriate mappings later.                            mime.removeParameter("charset");                            mime.removeParameter("class");                            mime.removeParameter("eoln");                            mime.removeParameter("terminators");                            value = mime.toString();                        }                    } catch (MimeTypeParseException e) {                        e.printStackTrace();                        continue;                    }                     DataFlavor flavor;                    try {                        flavor = new DataFlavor(value);                    } catch (Exception e) {                        try {                            flavor = new DataFlavor(value, (String)null);                        } catch (Exception ee) {                            ee.printStackTrace();                            continue;                        }                    }                     // For text/* flavors, store mappings in separate maps to                    // enable dynamic mapping generation at a run-time.                    if ("text".equals(flavor.getPrimaryType())) {                        store(value, key, getFlavorToNative());                        store(key, value, getNativeToFlavor());                    } else {                        store(flavor, key, getFlavorToNative());                        store(key, flavor, getNativeToFlavor());                    }                }            }        }    }     /**     * Copied from java.util.Properties.     */    private boolean continueLine (String line) {        int slashCount = 0;        int index = line.length() - 1;        while((index >= 0) && (line.charAt(index--) == '\\')) {            slashCount++;        }        return (slashCount % 2 == 1);    }     /**     * Copied from java.util.Properties.     */    private String loadConvert(String theString) {        char aChar;        int len = theString.length();        StringBuilder outBuffer = new StringBuilder(len);         for (int x = 0; x < len; ) {            aChar = theString.charAt(x++);            if (aChar == '\\') {                aChar = theString.charAt(x++);                if (aChar == 'u') {                    // Read the xxxx                    int value = 0;                    for (int i = 0; i < 4; i++) {                        aChar = theString.charAt(x++);                        switch (aChar) {                          case '0': case '1': case '2': case '3': case '4':                          case '5': case '6': case '7': case '8': case '9': {                             value = (value << 4) + aChar - '0';                             break;                          }                          case 'a': case 'b': case 'c':                          case 'd': case 'e': case 'f': {                             value = (value << 4) + 10 + aChar - 'a';                             break;                          }                          case 'A': case 'B': case 'C':                          case 'D': case 'E': case 'F': {                             value = (value << 4) + 10 + aChar - 'A';                             break;                          }                          default: {                              throw new IllegalArgumentException(                                           "Malformed \\uxxxx encoding.");                          }                        }                    }                    outBuffer.append((char)value);                } else {                    if (aChar == 't') {                        aChar = '\t';                    } else if (aChar == 'r') {                        aChar = '\r';                    } else if (aChar == 'n') {

Lines 1–500 of 1299.