--- old/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java 2014-12-12 18:00:23.221145200 +0400 +++ new/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java 2014-12-12 18:00:22.651112600 +0400 @@ -174,7 +174,7 @@ bytes = Normalizer.normalize(new String(bytes, "UTF8"), Form.NFC).getBytes("UTF8"); } - return super.translateBytesOrStream(stream, bytes, flavor, format, transferable); + return super.translateBytes(bytes, flavor, format, transferable); } @@ -261,16 +261,13 @@ private native byte[] imageDataToPlatformImageBytes(int[] rData, int nW, int nH); /** - * Translates either a byte array or an input stream which contain + * Translates a byte array which contains * platform-specific image data in the given format into an Image. */ - protected Image platformImageBytesOrStreamToImage(InputStream stream, byte[] bytes, long format) throws IOException { - byte[] imageData = bytes; - - if (imageData == null) - imageData = inputStreamToByteArray(stream); - - return getImageForByteStream(imageData); + protected Image platformImageBytesToImage(byte[] bytes, long format) + throws IOException + { + return getImageForByteStream(bytes); } private native Image getImageForByteStream(byte[] bytes); --- old/src/share/classes/java/awt/datatransfer/DataFlavor.java 2014-12-12 18:00:29.148484300 +0400 +++ new/src/share/classes/java/awt/datatransfer/DataFlavor.java 2014-12-12 18:00:27.921414100 +0400 @@ -170,6 +170,18 @@ } } + /* + * private initializer + */ + static private DataFlavor initHtmlDataFlavor(String htmlFlavorType) { + try { + return new DataFlavor ("text/html; class=java.lang.String;document=" + + htmlFlavorType + ";charset=Unicode"); + } catch (Exception e) { + return null; + } + } + /** * The DataFlavor representing a Java Unicode String class, * where: @@ -254,6 +266,46 @@ public static final String javaRemoteObjectMimeType = "application/x-java-remote-object"; /** + * Represents a piece of an HTML markup. The markup consists of the part + * selected on the source side. Therefore some tags in the markup may be + * unpaired. If the flavor is used to represent the data in + * a {@link Transferable} instance, no additional changes will be made. + * This DataFlavor instance represents the same HTML markup as DataFlavor + * instances which content MIME type does not contain document parameter + * and representation class is the String class. + *
+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection"); + + /** + * Represents a piece of an HTML markup. If possible, the markup received + * from a native system is supplemented with pair tags to be + * a well-formed HTML markup. If the flavor is used to represent the data in + * a {@link Transferable} instance, no additional changes will be made. + *
+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment"); + + /** + * Represents a piece of an HTML markup. If possible, the markup + * received from a native system is supplemented with additional + * tags to make up a well-formed HTML document. If the flavor is used to + * represent the data in a {@link Transferable} instance, + * no additional changes will be made. + *
+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all"); + + /** * Constructs a new DataFlavor. This constructor is * provided only for the purpose of supporting the * Externalizable interface. It is not @@ -957,24 +1009,35 @@ return false; } - if ("text".equals(getPrimaryType()) && - DataTransferer.doesSubtypeSupportCharset(this) && - representationClass != null && - !(isRepresentationClassReader() || - String.class.equals(representationClass) || - isRepresentationClassCharBuffer() || - DataTransferer.charArrayClass.equals(representationClass))) - { - String thisCharset = - DataTransferer.canonicalName(getParameter("charset")); - String thatCharset = - DataTransferer.canonicalName(that.getParameter("charset")); - if (thisCharset == null) { - if (thatCharset != null) { - return false; + if ("text".equals(getPrimaryType())) { + if (DataTransferer.doesSubtypeSupportCharset(this) && + representationClass != null && + !(isRepresentationClassReader() || + String.class.equals(representationClass) || + isRepresentationClassCharBuffer() || + DataTransferer.charArrayClass.equals(representationClass))) + { + String thisCharset = + DataTransferer.canonicalName(getParameter("charset")); + String thatCharset = + DataTransferer.canonicalName(that.getParameter("charset")); + if (thisCharset == null) { + if (thatCharset != null) { + return false; + } + } else { + if (!thisCharset.equals(thatCharset)) { + return false; + } } - } else { - if (!thisCharset.equals(thatCharset)) { + } + + if ("html".equals(getSubType()) && + this.getParameter("document") != null ) + { + if (!this.getParameter("document"). + equals(that.getParameter("document"))) + { return false; } } --- old/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2014-12-12 18:00:33.795750100 +0400 +++ new/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2014-12-12 18:00:33.075708900 +0400 @@ -41,7 +41,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -103,6 +103,11 @@ private static final String TEXT_PLAIN_BASE_TYPE = "text/plain"; /** + * A String representing text/html MIME type. + */ + private static final String HTML_TEXT_BASE_TYPE = "text/html"; + + /** * 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 @@ -115,7 +120,7 @@ * text DataFlavors). * Do not use the field directly, use getNativeToFlavor() instead. */ - private Map nativeToFlavor = new HashMap(); + private final Map> nativeToFlavor = new HashMap<>(); /** * Accessor to nativeToFlavor map. Since we use lazy initialization we must @@ -124,7 +129,7 @@ * * @return nativeToFlavor */ - private Map getNativeToFlavor() { + private Map> getNativeToFlavor() { if (!isMapInitialized) { initSystemFlavorMap(); } @@ -136,7 +141,7 @@ * native Strings. * Do not use the field directly, use getFlavorToNative() instead. */ - private Map flavorToNative = new HashMap(); + private final Map flavorToNative = new HashMap(); /** * Accessor to flavorToNative map. Since we use lazy initialization we must @@ -411,14 +416,17 @@ } } - // For text/* flavors, store mappings in separate maps to - // enable dynamic mapping generation at a run-time. + final LinkedHashSet dfs = new LinkedHashSet<>(); + + dfs.add(flavor); + if ("text".equals(flavor.getPrimaryType())) { - store(value, key, getFlavorToNative()); - store(key, value, getNativeToFlavor()); - } else { - store(flavor, key, getFlavorToNative()); - store(key, flavor, getNativeToFlavor()); + dfs.addAll(convertMimeTypeToDataFlavors(value)); + } + + for (DataFlavor df : dfs) { + store(df, key, getFlavorToNative()); + store(key, df, getNativeToFlavor()); } } } @@ -520,7 +528,7 @@ * only if the specified native is encoded as a Java MIME type. */ private List nativeToFlavorLookup(String nat) { - List flavors = (List)getNativeToFlavor().get(nat); + List flavors = getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { DataTransferer transferer = DataTransferer.getInstance(); @@ -615,7 +623,7 @@ getNativesForFlavorCache.remove(flav); getNativesForFlavorCache.remove(null); - List flavors = (List)getNativeToFlavor().get(encoded); + List flavors = getNativeToFlavor().get(encoded); if (flavors == null) { flavors = new ArrayList(1); getNativeToFlavor().put(encoded, flavors); @@ -671,7 +679,7 @@ } if (flav == null) { - retval = new ArrayList(getNativeToFlavor().keySet()); + retval = new ArrayList(getNativeToFlavor().keySet()); } else if (disabledMappingGenerationKeys.contains(flav)) { // In this case we shouldn't synthesize a native for this flavor, // since its mappings were explicitly specified. @@ -799,140 +807,162 @@ } } - LinkedList retval = new LinkedList(); + final LinkedHashSet returnValue = + new LinkedHashSet<>(); if (nat == null) { - List natives = getNativesForFlavor(null); - HashSet dups = new HashSet(natives.size()); + final List natives = getNativesForFlavor(null); - for (Iterator natives_iter = natives.iterator(); - natives_iter.hasNext(); ) + for (String n : natives) { - List flavors = - getFlavorsForNative((String)natives_iter.next()); - for (Iterator flavors_iter = flavors.iterator(); - flavors_iter.hasNext(); ) + final List flavors = getFlavorsForNative(n); + + for (DataFlavor df : flavors) { - Object flavor = flavors_iter.next(); - if (dups.add(flavor)) { - retval.add(flavor); - } + returnValue.add(df); } } } else { - List flavors = nativeToFlavorLookup(nat); + + final List flavors = nativeToFlavorLookup(nat); if (disabledMappingGenerationKeys.contains(nat)) { return flavors; } - HashSet dups = new HashSet(flavors.size()); + final List flavorsAndBaseTypes = + nativeToFlavorLookup(nat); + + for (DataFlavor df : flavorsAndBaseTypes) { + returnValue.add(df); + if ("text".equals(df.getPrimaryType())) { + try { + returnValue.addAll( + convertMimeTypeToDataFlavors( + new MimeType(df.getMimeType() + ).getBaseType())); + } catch (MimeTypeParseException e) { + e.printStackTrace(); + } + } + } + + } + + final ArrayList arrayList = new ArrayList(returnValue); + getFlavorsForNativeCache.put(nat, new SoftReference(arrayList)); + return (List)arrayList.clone(); + } + + private static LinkedHashSet convertMimeTypeToDataFlavors( + final String baseType) { - List flavorsAndbaseTypes = nativeToFlavorLookup(nat); + final LinkedHashSet returnValue = + new LinkedHashSet(); - for (Iterator flavorsAndbaseTypes_iter = - flavorsAndbaseTypes.iterator(); - flavorsAndbaseTypes_iter.hasNext(); ) + String subType = null; + + try { + final MimeType mimeType = new MimeType(baseType); + subType = mimeType.getSubType(); + } catch (MimeTypeParseException mtpe) { + // Cannot happen, since we checked all mappings + // on load from flavormap.properties. + assert(false); + } + + if (DataTransferer.doesSubtypeSupportCharset(subType, null)) { + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) { - Object value = flavorsAndbaseTypes_iter.next(); - if (value instanceof String) { - String baseType = (String)value; - String subType = null; + returnValue.add(DataFlavor.stringFlavor); + } + + for (String unicodeClassName : UNICODE_TEXT_CLASSES) { + final String mimeType = baseType + ";charset=Unicode;class=" + + unicodeClassName; + + final LinkedHashSet mimeTypes = + handleHtmlMimeTypes(baseType, mimeType); + for (String mt : mimeTypes) { + DataFlavor toAdd = null; try { - MimeType mimeType = new MimeType(baseType); - subType = mimeType.getSubType(); - } catch (MimeTypeParseException mtpe) { - // Cannot happen, since we checked all mappings - // on load from flavormap.properties. - assert(false); - } - if (DataTransferer.doesSubtypeSupportCharset(subType, - null)) { - if (TEXT_PLAIN_BASE_TYPE.equals(baseType) && - dups.add(DataFlavor.stringFlavor)) - { - retval.add(DataFlavor.stringFlavor); - } - - for (int i = 0; i < UNICODE_TEXT_CLASSES.length; i++) { - DataFlavor toAdd = null; - try { - toAdd = new DataFlavor - (baseType + ";charset=Unicode;class=" + - UNICODE_TEXT_CLASSES[i]); - } catch (ClassNotFoundException cannotHappen) { - } - if (dups.add(toAdd)) { - retval.add(toAdd); - } - } + toAdd = new DataFlavor(mt); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } + } - for (Iterator charset_iter = - DataTransferer.standardEncodings(); - charset_iter.hasNext(); ) - { - String charset = (String)charset_iter.next(); + for (String charset : DataTransferer.standardEncodings()) { - for (int i = 0; i < ENCODED_TEXT_CLASSES.length; - i++) - { - DataFlavor toAdd = null; - try { - toAdd = new DataFlavor - (baseType + ";charset=" + charset + - ";class=" + ENCODED_TEXT_CLASSES[i]); - } catch (ClassNotFoundException cannotHappen) { - } + for (String encodedTextClass : ENCODED_TEXT_CLASSES) { + final String mimeType = + baseType + ";charset=" + charset + + ";class=" + encodedTextClass; - // Check for equality to plainTextFlavor so - // that we can ensure that the exact charset of - // plainTextFlavor, not the canonical charset - // or another equivalent charset with a - // different name, is used. - if (toAdd.equals(DataFlavor.plainTextFlavor)) { - toAdd = DataFlavor.plainTextFlavor; - } + final LinkedHashSet mimeTypes = + handleHtmlMimeTypes(baseType, mimeType); - if (dups.add(toAdd)) { - retval.add(toAdd); - } - } - } + for (String mt : mimeTypes) { - if (TEXT_PLAIN_BASE_TYPE.equals(baseType) && - dups.add(DataFlavor.plainTextFlavor)) - { - retval.add(DataFlavor.plainTextFlavor); - } - } else { - // Non-charset text natives should be treated as - // opaque, 8-bit data in any of its various - // representations. - for (int i = 0; i < ENCODED_TEXT_CLASSES.length; i++) { - DataFlavor toAdd = null; - try { - toAdd = new DataFlavor(baseType + - ";class=" + ENCODED_TEXT_CLASSES[i]); - } catch (ClassNotFoundException cannotHappen) { - } + DataFlavor df = null; - if (dups.add(toAdd)) { - retval.add(toAdd); + try { + df = new DataFlavor(mt); + // Check for equality to plainTextFlavor so + // that we can ensure that the exact charset of + // plainTextFlavor, not the canonical charset + // or another equivalent charset with a + // different name, is used. + if (df.equals(DataFlavor.plainTextFlavor)) { + df = DataFlavor.plainTextFlavor; } + } catch (ClassNotFoundException cannotHappen) { } - } - } else { - DataFlavor flavor = (DataFlavor)value; - if (dups.add(flavor)) { - retval.add(flavor); + + returnValue.add(df); } } } + + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) + { + returnValue.add(DataFlavor.plainTextFlavor); + } + } else { + // Non-charset text natives should be treated as + // opaque, 8-bit data in any of its various + // representations. + for (String encodedTextClassName : ENCODED_TEXT_CLASSES) { + DataFlavor toAdd = null; + try { + toAdd = new DataFlavor(baseType + + ";class=" + encodedTextClassName); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } } + return returnValue; + } - ArrayList arrayList = new ArrayList(retval); - getFlavorsForNativeCache.put(nat, new SoftReference(arrayList)); - return (List)arrayList.clone(); + private static final String [] htmlDocumntTypes = + new String [] {"all", "selection", "fragment"}; + + private static LinkedHashSet handleHtmlMimeTypes( + String baseType, String mimeType) { + + LinkedHashSet returnValues = new LinkedHashSet<>(); + + if (HTML_TEXT_BASE_TYPE.equals(baseType)) { + for (String documentType : htmlDocumntTypes) { + returnValues.add(mimeType + ";document=" + documentType); + } + } else { + returnValues.add(mimeType); + } + + return returnValues; } /** --- old/src/share/classes/sun/awt/datatransfer/DataTransferer.java 2014-12-12 18:00:38.340010000 +0400 +++ new/src/share/classes/sun/awt/datatransfer/DataTransferer.java 2014-12-12 18:00:37.540964300 +0400 @@ -171,12 +171,12 @@ * Lazy initialization of Standard Encodings. */ private static class StandardEncodingsHolder { - private static final SortedSet standardEncodings = load(); + private static final SortedSet standardEncodings = load(); - private static SortedSet load() { + private static SortedSet load() { final Comparator comparator = new CharsetComparator(IndexedComparator.SELECT_WORST); - final SortedSet tempSet = new TreeSet(comparator); + final SortedSet tempSet = new TreeSet(comparator); tempSet.add("US-ASCII"); tempSet.add("ISO-8859-1"); tempSet.add("UTF-8"); @@ -523,8 +523,8 @@ * So as to avoid loading all available character converters, optional, * non-standard, character sets are not included. */ - public static Iterator standardEncodings() { - return StandardEncodingsHolder.standardEncodings.iterator(); + public static Set standardEncodings() { + return StandardEncodingsHolder.standardEncodings; } /** @@ -1063,17 +1063,10 @@ * * Native to Java string conversion */ - private String translateBytesOrStreamToString(InputStream str, byte[] bytes, - long format, - Transferable localeTransferable) + private String translateBytesToString(byte[] bytes, long format, + Transferable localeTransferable) throws IOException { - // A String holds all of its data in memory at one time, so - // we can't avoid reading the entire InputStream at this point. - if (bytes == null) { - bytes = inputStreamToByteArray(str); - } - str.close(); Long lFormat = Long.valueOf(format); String charset = getBestCharsetForTextFormat(lFormat, localeTransferable); @@ -1216,13 +1209,13 @@ ("cannot transfer non-text data as Reader"); } - Reader r = (Reader)obj; StringBuffer buf = new StringBuffer(); - int c; - while ((c = r.read()) != -1) { - buf.append((char)c); + try (Reader r = (Reader)obj) { + int c; + while ((c = r.read()) != -1) { + buf.append((char)c); + } } - r.close(); return translateTransferableString( buf.toString(), @@ -1304,7 +1297,7 @@ return bytes; } - ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] theByteArray = null; // Target data is a file list. Source data must be a // java.util.List which contains java.io.File or String instances. @@ -1319,8 +1312,9 @@ final ArrayList fileList = castToFiles(list, userProtectionDomain); - bos = convertFileListToBytes(fileList); - + try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) { + theByteArray = bos.toByteArray(); + } // Target data is a URI list. Source data must be a // java.util.List which contains java.io.File or String instances. @@ -1355,57 +1349,72 @@ } byte[] eoln = "\r\n".getBytes(targetCharset); - for (int i = 0; i < uriList.size(); i++) { - byte[] bytes = uriList.get(i).getBytes(targetCharset); - bos.write(bytes, 0, bytes.length); - bos.write(eoln, 0, eoln.length); + + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + for (int i = 0; i < uriList.size(); i++) { + byte[] bytes = uriList.get(i).getBytes(targetCharset); + bos.write(bytes, 0, bytes.length); + bos.write(eoln, 0, eoln.length); + } + theByteArray = bos.toByteArray(); } // Source data is an InputStream. For arbitrary flavors, just grab the // bytes and dump them into a byte array. For text flavors, decode back // to a String and recur to reencode according to the requested format. } else if (flavor.isRepresentationClassInputStream()) { - InputStream is = (InputStream)obj; - boolean eof = false; - int avail = is.available(); - byte[] tmp = new byte[avail > 8192 ? avail : 8192]; - do { - int ret; - if (!(eof = (ret = is.read(tmp, 0, tmp.length)) == -1)) { - bos.write(tmp, 0, ret); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + try (InputStream is = (InputStream)obj) { + boolean eof = false; + int avail = is.available(); + byte[] tmp = new byte[avail > 8192 ? avail : 8192]; + do { + int aValue; + if (!(eof = (aValue = is.read(tmp, 0, tmp.length)) == -1)) { + bos.write(tmp, 0, aValue); + } + } while (!eof); } - } while (!eof); - is.close(); - if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) { - byte[] bytes = bos.toByteArray(); - bos.close(); - String sourceEncoding = DataTransferer.getTextCharset(flavor); - return translateTransferableString( - new String(bytes, sourceEncoding), - format); + if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) { + byte[] bytes = bos.toByteArray(); + String sourceEncoding = DataTransferer.getTextCharset(flavor); + return translateTransferableString( + new String(bytes, sourceEncoding), + format); + } + theByteArray = bos.toByteArray(); } + + // Source data is an RMI object } else if (flavor.isRepresentationClassRemote()) { + Object mo = RMI.newMarshalledObject(obj); - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(mo); - oos.close(); + theByteArray = convertObjectToBytes(mo); - // Source data is Serializable + // Source data is Serializable } else if (flavor.isRepresentationClassSerializable()) { - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(obj); - oos.close(); + + theByteArray = convertObjectToBytes(obj); } else { throw new IOException("data translation failed"); } - byte[] ret = bos.toByteArray(); - bos.close(); - return ret; + + + return theByteArray; + } + + private static byte[] convertObjectToBytes(Object object) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos)) + { + oos.writeObject(object); + return bos.toByteArray(); + } } protected abstract ByteArrayOutputStream convertFileListToBytes(ArrayList fileList) throws IOException; @@ -1560,38 +1569,8 @@ long format, Transferable localeTransferable) throws IOException { - return translateBytesOrStream(null, bytes, flavor, format, - localeTransferable); - } - - public Object translateStream(InputStream str, DataFlavor flavor, - long format, Transferable localeTransferable) - throws IOException - { - return translateBytesOrStream(str, null, flavor, format, - localeTransferable); - } - - - /** - * Primary translation function for translating either a byte array or - * an InputStream into an Object, given a source format and a target - * DataFlavor. - * - * One of str/bytes is non-null; the other is null. - * The conversion from byte[] to InputStream is cheap, so do that - * immediately if necessary. The opposite conversion is expensive, - * so avoid it if possible. - */ - protected Object translateBytesOrStream(InputStream str, byte[] bytes, - DataFlavor flavor, long format, - Transferable localeTransferable) - throws IOException - { - if (str == null) { - str = new ByteArrayInputStream(bytes); - } + Object theObject = null; // Source data is a file list. Use the dragQueryFile native function to // do most of the decoding. Then wrap File objects around the String @@ -1600,12 +1579,8 @@ if (!DataFlavor.javaFileListFlavor.equals(flavor)) { throw new IOException("data translation failed"); } - if (bytes == null) { - bytes = inputStreamToByteArray(str); - } String[] filenames = dragQueryFile(bytes); if (filenames == null) { - str.close(); return null; } @@ -1614,178 +1589,203 @@ for (int i = 0; i < filenames.length; i++) { files[i] = new File(filenames[i]); } - str.close(); // Turn the list of Files into a List and return - return Arrays.asList(files); + theObject = Arrays.asList(files); - // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor - // where possible. - } else if (isURIListFormat(format) && DataFlavor.javaFileListFlavor.equals(flavor)) { - try { - URI uris[] = dragQueryURIs(str, bytes, format, localeTransferable); - if (uris == null) { - return null; - } - ArrayList files = new ArrayList(); - for (URI uri : uris) { - try { - files.add(new File(uri)); - } catch (IllegalArgumentException illegalArg) { - // When converting from URIs to less generic files, - // common practice (Wine, SWT) seems to be to - // silently drop the URIs that aren't local files. - } - } - return files; - } finally { - str.close(); - } - - // Target data is a String. Strip terminating NUL bytes. Decode bytes - // into characters. Search-and-replace EOLN. + // Target data is a String. Strip terminating NUL bytes. Decode bytes + // into characters. Search-and-replace EOLN. } else if (String.class.equals(flavor.getRepresentationClass()) && - isFlavorCharsetTextType(flavor) && isTextFormat(format)) { + isFlavorCharsetTextType(flavor) && isTextFormat(format)) { - return translateBytesOrStreamToString( - str, bytes, - format, localeTransferable); - - // Special hack to maintain backwards-compatibility with the brokenness - // of StringSelection. Return a StringReader instead of an InputStream. - // Recur to obtain String and encapsulate. - } else if (DataFlavor.plainTextFlavor.equals(flavor)) { - return new StringReader(translateBytesOrStreamToString( - str, bytes, - format, localeTransferable)); - - // Target data is an InputStream. For arbitrary flavors, just return - // the raw bytes. For text flavors, decode to strip terminators and - // search-and-replace EOLN, then reencode according to the requested - // flavor. - } else if (flavor.isRepresentationClassInputStream()) { - return translateBytesOrStreamToInputStream(str, flavor, format, - localeTransferable); + theObject = translateBytesToString(bytes, format, localeTransferable); - // Target data is a Reader. Obtain data in InputStream format, encoded - // as "Unicode" (utf-16be). Then use an InputStreamReader to decode - // back to chars on demand. + // Target data is a Reader. Obtain data in InputStream format, encoded + // as "Unicode" (utf-16be). Then use an InputStreamReader to decode + // back to chars on demand. } else if (flavor.isRepresentationClassReader()) { - if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) { - throw new IOException - ("cannot transfer non-text data as Reader"); + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { + theObject = translateStream(bais, + flavor, format, localeTransferable); } - - InputStream is = (InputStream) - translateBytesOrStreamToInputStream - (str, DataFlavor.plainTextFlavor, format, - localeTransferable); - String unicode = - DataTransferer.getTextCharset(DataFlavor.plainTextFlavor); - Reader reader = new InputStreamReader(is, unicode); - - return constructFlavoredObject(reader, flavor, Reader.class); - - // Target data is a CharBuffer. Recur to obtain String and wrap. + // Target data is a CharBuffer. Recur to obtain String and wrap. } else if (flavor.isRepresentationClassCharBuffer()) { if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) { throw new IOException - ("cannot transfer non-text data as CharBuffer"); + ("cannot transfer non-text data as CharBuffer"); } - CharBuffer buffer = CharBuffer.wrap(translateBytesOrStreamToString( - str, bytes, - format, localeTransferable)); + CharBuffer buffer = CharBuffer.wrap( + translateBytesToString(bytes,format, localeTransferable)); - return constructFlavoredObject(buffer, flavor, CharBuffer.class); + theObject = constructFlavoredObject(buffer, flavor, CharBuffer.class); - // Target data is a char array. Recur to obtain String and convert to - // char array. + // Target data is a char array. Recur to obtain String and convert to + // char array. } else if (charArrayClass.equals(flavor.getRepresentationClass())) { if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) { throw new IOException - ("cannot transfer non-text data as char array"); + ("cannot transfer non-text data as char array"); } - return translateBytesOrStreamToString( - str, bytes, - format, localeTransferable).toCharArray(); - - // Target data is a ByteBuffer. For arbitrary flavors, just return - // the raw bytes. For text flavors, convert to a String to strip - // terminators and search-and-replace EOLN, then reencode according to - // the requested flavor. + theObject = translateBytesToString( + bytes, format, localeTransferable).toCharArray(); + + // Target data is a ByteBuffer. For arbitrary flavors, just return + // the raw bytes. For text flavors, convert to a String to strip + // terminators and search-and-replace EOLN, then reencode according to + // the requested flavor. } else if (flavor.isRepresentationClassByteBuffer()) { if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) { - bytes = translateBytesOrStreamToString( - str, bytes, - format, localeTransferable - ).getBytes( - DataTransferer.getTextCharset(flavor) - ); - } else { - if (bytes == null) { - bytes = inputStreamToByteArray(str); - } + bytes = translateBytesToString( + bytes, format, localeTransferable).getBytes( + DataTransferer.getTextCharset(flavor) + ); } ByteBuffer buffer = ByteBuffer.wrap(bytes); - return constructFlavoredObject(buffer, flavor, ByteBuffer.class); + theObject = constructFlavoredObject(buffer, flavor, ByteBuffer.class); - // Target data is a byte array. For arbitrary flavors, just return - // the raw bytes. For text flavors, convert to a String to strip - // terminators and search-and-replace EOLN, then reencode according to - // the requested flavor. + // Target data is a byte array. For arbitrary flavors, just return + // the raw bytes. For text flavors, convert to a String to strip + // terminators and search-and-replace EOLN, then reencode according to + // the requested flavor. } else if (byteArrayClass.equals(flavor.getRepresentationClass())) { if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) { - return translateBytesOrStreamToString( - str, bytes, - format, localeTransferable - ).getBytes( - DataTransferer.getTextCharset(flavor) - ); + theObject = translateBytesToString( + bytes, format, localeTransferable + ).getBytes(DataTransferer.getTextCharset(flavor)); } else { - return (bytes != null) ? bytes : inputStreamToByteArray(str); + theObject = bytes; } - // Target data is an RMI object - } else if (flavor.isRepresentationClassRemote()) { - try { - byte[] ba = inputStreamToByteArray(str); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba)); - Object ret = RMI.getMarshalledObject(ois.readObject()); - ois.close(); - str.close(); - return ret; - } catch (Exception e) { - throw new IOException(e.getMessage()); + // Target data is an InputStream. For arbitrary flavors, just return + // the raw bytes. For text flavors, decode to strip terminators and + // search-and-replace EOLN, then reencode according to the requested + // flavor. + } else if (flavor.isRepresentationClassInputStream()) { + + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { + theObject = translateStream(bais, flavor, format, localeTransferable); } - // Target data is Serializable + // Target data is Serializable } else if (flavor.isRepresentationClassSerializable()) { - try { - byte[] ba = inputStreamToByteArray(str); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba)); - Object ret = ois.readObject(); - ois.close(); - str.close(); - return ret; - } catch (Exception e) { - throw new IOException(e.getMessage()); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { + theObject = translateStream(bais, flavor, format, localeTransferable); } - // Target data is Image + // Target data is Image } else if (DataFlavor.imageFlavor.equals(flavor)) { if (!isImageFormat(format)) { throw new IOException("data translation failed"); } - Image image = platformImageBytesOrStreamToImage(str, bytes, format); - str.close(); - return image; + theObject = platformImageBytesToImage(bytes, format); + } + + if (theObject == null) { + throw new IOException("data translation failed"); + } + + return theObject; + + } + + /** + * Primary translation function for translating + * an InputStream into an Object, given a source format and a target + * DataFlavor. + */ + public Object translateStream(InputStream str, DataFlavor flavor, + long format, Transferable localeTransferable) + throws IOException + { + + Object theObject = null; + // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor + // where possible. + if (isURIListFormat(format) + && DataFlavor.javaFileListFlavor.equals(flavor)) + { + + URI uris[] = dragQueryURIs(str, format, localeTransferable); + if (uris == null) { + return null; + } + ArrayList files = new ArrayList(); + for (URI uri : uris) { + try { + files.add(new File(uri)); + } catch (IllegalArgumentException illegalArg) { + // When converting from URIs to less generic files, + // common practice (Wine, SWT) seems to be to + // silently drop the URIs that aren't local files. + } + } + theObject = files; + + // Special hack to maintain backwards-compatibility with the brokenness + // of StringSelection. Return a StringReader instead of an InputStream. + // Recur to obtain String and encapsulate. + } else if (DataFlavor.plainTextFlavor.equals(flavor)) { + theObject = new StringReader(translateBytesToString( + inputStreamToByteArray(str), + format, localeTransferable)); + + // Target data is an InputStream. For arbitrary flavors, just return + // the raw bytes. For text flavors, decode to strip terminators and + // search-and-replace EOLN, then reencode according to the requested + // flavor. + } else if (flavor.isRepresentationClassInputStream()) { + theObject = translateStreamToInputStream(str, flavor, format, + localeTransferable); + + // Target data is a Reader. Obtain data in InputStream format, encoded + // as "Unicode" (utf-16be). Then use an InputStreamReader to decode + // back to chars on demand. + } else if (flavor.isRepresentationClassReader()) { + if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) { + throw new IOException + ("cannot transfer non-text data as Reader"); + } + + InputStream is = (InputStream)translateStreamToInputStream( + str, DataFlavor.plainTextFlavor, + format, localeTransferable); + + String unicode = DataTransferer.getTextCharset(DataFlavor.plainTextFlavor); + + Reader reader = new InputStreamReader(is, unicode); + + theObject = constructFlavoredObject(reader, flavor, Reader.class); + + // Target data is an RMI object + } else if (flavor.isRepresentationClassRemote()) { + + try (ObjectInputStream ois = + new ObjectInputStream(str)) + { + theObject = RMI.getMarshalledObject(ois.readObject()); + }catch (Exception e) { + throw new IOException(e.getMessage()); + } + + // Target data is Serializable + } else if (flavor.isRepresentationClassSerializable()) { + try (ObjectInputStream ois = + new ObjectInputStream(str)) + { + theObject = ois.readObject(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } } - throw new IOException("data translation failed"); + + return theObject; + } /** @@ -1793,7 +1793,7 @@ * ReencodingInputStream will decode and reencode the InputStream on demand * so that we can strip terminators and search-and-replace EOLN. */ - private Object translateBytesOrStreamToInputStream + private Object translateStreamToInputStream (InputStream str, DataFlavor flavor, long format, Transferable localeTransferable) throws IOException { @@ -2049,7 +2049,6 @@ * Decodes URIs from either a byte array or a stream. */ protected URI[] dragQueryURIs(InputStream stream, - byte[] bytes, long format, Transferable localeTransferable) throws IOException @@ -2062,10 +2061,10 @@ * Translates either a byte array or an input stream which contain * platform-specific image data in the given format into an Image. */ - protected abstract Image platformImageBytesOrStreamToImage(InputStream str, - byte[] bytes, - long format) - throws IOException; + + + protected abstract Image platformImageBytesToImage( + byte[] bytes,long format) throws IOException; /** * Translates either a byte array or an input stream which contain @@ -2073,13 +2072,9 @@ * * @param mimeType image MIME type, such as: image/png, image/jpeg, image/gif */ - protected Image standardImageBytesOrStreamToImage(InputStream inputStream, - byte[] bytes, - String mimeType) - throws IOException { - if (inputStream == null) { - inputStream = new ByteArrayInputStream(bytes); - } + protected Image standardImageBytesToImage( + byte[] bytes, String mimeType) throws IOException + { Iterator readerIterator = ImageIO.getImageReadersByMIMEType(mimeType); @@ -2092,9 +2087,9 @@ while (readerIterator.hasNext()) { ImageReader imageReader = (ImageReader)readerIterator.next(); - try { + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { ImageInputStream imageInputStream = - ImageIO.createImageInputStream(inputStream); + ImageIO.createImageInputStream(bais); try { ImageReadParam param = imageReader.getDefaultReadParam(); @@ -2424,15 +2419,16 @@ protected static byte[] inputStreamToByteArray(InputStream str) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int len = 0; - byte[] buf = new byte[8192]; + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + int len = 0; + byte[] buf = new byte[8192]; - while ((len = str.read(buf)) != -1) { - baos.write(buf, 0, len); - } + while ((len = str.read(buf)) != -1) { + baos.write(buf, 0, len); + } - return baos.toByteArray(); + return baos.toByteArray(); + } } /** --- old/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java 2014-12-12 18:00:43.368297600 +0400 +++ new/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java 2014-12-12 18:00:42.534249900 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, 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 @@ -57,7 +57,6 @@ import sun.awt.SunToolkit; import sun.awt.datatransfer.DataTransferer; import sun.awt.datatransfer.ToolkitThreadBlockedHandler; -import sun.security.util.SecurityConstants; /** *

@@ -239,13 +238,6 @@ if (localTransferable != null) { return localTransferable.getTransferData(df); - } else if (df.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType)) { - // Workaround to JDK-8024061: Exception thrown when drag and drop - // between two components is executed quickly. - // It is expected localTransferable is not null if javaJVMLocalObjectMimeType - // is used. Executing further results in ClassCastException, so null is - // returned here as no transfer data is available in this case. - return null; } if (dropStatus != STATUS_ACCEPT || dropComplete) { @@ -267,6 +259,7 @@ } final long format = lFormat.longValue(); + Object ret = getNativeData(format); if (ret instanceof byte[]) { @@ -277,11 +270,14 @@ throw new InvalidDnDOperationException(e.getMessage()); } } else if (ret instanceof InputStream) { + InputStream inputStream = (InputStream)ret; try { return DataTransferer.getInstance(). - translateStream((InputStream)ret, df, format, this); + translateStream(inputStream, df, format, this); } catch (IOException e) { throw new InvalidDnDOperationException(e.getMessage()); + } finally { + inputStream.close(); } } else { throw new IOException("no native data was transfered"); --- old/src/solaris/classes/sun/awt/X11/XDataTransferer.java 2014-12-12 18:00:48.865612000 +0400 +++ new/src/solaris/classes/sun/awt/X11/XDataTransferer.java 2014-12-12 18:00:47.786550300 +0400 @@ -212,10 +212,9 @@ * Translates either a byte array or an input stream which contain * platform-specific image data in the given format into an Image. */ - protected Image platformImageBytesOrStreamToImage(InputStream inputStream, - byte[] bytes, - long format) - throws IOException { + protected Image platformImageBytesToImage( + byte[] bytes, long format) throws IOException + { String mimeType = null; if (format == PNG_ATOM.getAtom()) { mimeType = "image/png"; @@ -235,7 +234,7 @@ } } if (mimeType != null) { - return standardImageBytesOrStreamToImage(inputStream, bytes, mimeType); + return standardImageBytesToImage(bytes, mimeType); } else { String nativeFormat = getNativeForFormat(format); throw new IOException("Translation from " + nativeFormat + @@ -330,8 +329,8 @@ * a valid MIME and return a list of flavors to which the data in this MIME * type can be translated by the Data Transfer subsystem. */ - public List getPlatformMappingsForNative(String nat) { - List flavors = new ArrayList(); + public List getPlatformMappingsForNative(String nat) { + List flavors = new ArrayList(); if (nat == null) { return flavors; @@ -346,16 +345,14 @@ return flavors; } - Object value = df; + DataFlavor value = df; final String primaryType = df.getPrimaryType(); final String baseType = primaryType + "/" + df.getSubType(); // For text formats we map natives to MIME strings instead of data // flavors to enable dynamic text native-to-flavor mapping generation. // See SystemFlavorMap.getFlavorsForNative() for details. - if ("text".equals(primaryType)) { - value = primaryType + "/" + df.getSubType(); - } else if ("image".equals(primaryType)) { + if ("image".equals(primaryType)) { Iterator readers = ImageIO.getImageReadersByMIMEType(baseType); if (readers.hasNext()) { flavors.add(DataFlavor.imageFlavor); @@ -438,16 +435,13 @@ } } } else if (DataTransferer.isFlavorCharsetTextType(df)) { - final Iterator iter = DataTransferer.standardEncodings(); - // stringFlavor is semantically equivalent to the standard // "text/plain" MIME type. if (DataFlavor.stringFlavor.equals(df)) { baseType = "text/plain"; } - while (iter.hasNext()) { - String encoding = (String)iter.next(); + for (String encoding : DataTransferer.standardEncodings()) { if (!encoding.equals(charset)) { natives.add(baseType + ";charset=" + encoding); } --- old/src/windows/classes/sun/awt/windows/WDataTransferer.java 2014-12-12 18:00:54.228918800 +0400 +++ new/src/windows/classes/sun/awt/windows/WDataTransferer.java 2014-12-12 18:00:53.305866000 +0400 @@ -186,32 +186,56 @@ DataFlavor flavor, long format) throws IOException { - byte[] bytes = super.translateTransferable(contents, flavor, format); - + byte[] bytes = null; if (format == CF_HTML) { - bytes = HTMLCodec.convertToHTMLFormat(bytes); + if (contents.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor)) { + // if a user provides data represented by + // DataFlavor.selectionHtmlFlavor format, we use this + // type to store the data in the native clipboard + bytes = super.translateTransferable(contents, + DataFlavor.selectionHtmlFlavor, + format); + } else if (contents.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) { + // if we cannot get data represented by the + // DataFlavor.selectionHtmlFlavor format + // but the DataFlavor.allHtmlFlavor format is avialable + // we belive that the user knows how to represent + // the data and how to mark up selection in a + // system specific manner. Therefor, we use this data + bytes = super.translateTransferable(contents, + DataFlavor.allHtmlFlavor, + format); + } else { + // handle other html flavor types, including custom and + // fragment ones + bytes = HTMLCodec.convertToHTMLFormat(super.translateTransferable(contents, flavor, format)); + } + } else { + // we handle non-html types basing on their + // flavors + bytes = super.translateTransferable(contents, flavor, format); } return bytes; } - protected Object translateBytesOrStream(InputStream str, byte[] bytes, - DataFlavor flavor, long format, - Transferable localeTransferable) - throws IOException - { + // The stream is closed as a closable object + public Object translateStream(InputStream str, + DataFlavor flavor, long format, + Transferable localeTransferable) + throws IOException { if (format == CF_HTML && flavor.isFlavorTextType()) { - if (str == null) { - str = new ByteArrayInputStream(bytes); - bytes = null; - } + str = new HTMLCodec(str, + EHTMLReadMode.getEHTMLReadMode(flavor)); - str = new HTMLCodec(str, EHTMLReadMode.HTML_READ_ALL); } + return super.translateStream(str, flavor, format, + localeTransferable); + } + + public Object translateBytes(byte[] bytes, DataFlavor flavor, long format, + Transferable localeTransferable) throws IOException { if (format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW) { - if (null != str ) { - str.close(); - } if (bytes == null || !DataFlavor.javaFileListFlavor.equals(flavor)) { throw new IOException("data translation failed"); } @@ -233,28 +257,23 @@ } if (format == CFSTR_INETURL && - URL.class.equals(flavor.getRepresentationClass())) + URL.class.equals(flavor.getRepresentationClass())) { - if (bytes == null) { - bytes = inputStreamToByteArray(str); - str = null; - } String charset = getDefaultTextCharset(); - if (localeTransferable != null && localeTransferable. - isDataFlavorSupported(javaTextEncodingFlavor)) + if (localeTransferable != null && localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor)) { try { charset = new String((byte[])localeTransferable. - getTransferData(javaTextEncodingFlavor), - "UTF-8"); + getTransferData(javaTextEncodingFlavor), "UTF-8"); } catch (UnsupportedFlavorException cannotHappen) { } } return new URL(new String(bytes, charset)); } - return super.translateBytesOrStream(str, bytes, flavor, format, - localeTransferable); + return super.translateBytes(bytes , flavor, format, + localeTransferable); + } public boolean isLocaleDependentTextFormat(long format) { @@ -275,18 +294,18 @@ protected String getNativeForFormat(long format) { return (format < predefinedClipboardNames.length) - ? predefinedClipboardNames[(int)format] - : getClipboardFormatName(format); + ? predefinedClipboardNames[(int)format] + : getClipboardFormatName(format); } private final ToolkitThreadBlockedHandler handler = - new WToolkitThreadBlockedHandler(); + new WToolkitThreadBlockedHandler(); public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() { return handler; } - /** + /** * Calls the Win32 RegisterClipboardFormat function to register * a non-standard format. */ @@ -300,12 +319,12 @@ public boolean isImageFormat(long format) { return format == CF_DIB || format == CF_ENHMETAFILE || - format == CF_METAFILEPICT || format == CF_PNG || - format == CF_JFIF; + format == CF_METAFILEPICT || format == CF_PNG || + format == CF_JFIF; } protected byte[] imageToPlatformBytes(Image image, long format) - throws IOException { + throws IOException { String mimeType = null; if (format == CF_PNG) { mimeType = "image/png"; @@ -347,11 +366,11 @@ int[] nBits = {8, 8, 8}; int[] bOffs = {2, 1, 0}; ColorModel colorModel = - new ComponentColorModel(cs, nBits, false, false, - Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, DataBuffer.TYPE_BYTE); WritableRaster raster = - Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, - width * 3 + pad, 3, bOffs, null); + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 3 + pad, 3, bOffs, null); BufferedImage bimage = new BufferedImage(colorModel, raster, false, null); @@ -359,7 +378,7 @@ // top-down DIBs. // So we flip the image vertically and create a bottom-up DIB. AffineTransform imageFlipTransform = - new AffineTransform(1, 0, 0, -1, 0, height); + new AffineTransform(1, 0, 0, -1, 0, height); Graphics2D g2d = bimage.createGraphics(); @@ -378,7 +397,7 @@ private static final byte [] UNICODE_NULL_TERMINATOR = new byte [] {0,0}; protected ByteArrayOutputStream convertFileListToBytes(ArrayList fileList) - throws IOException + throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -402,10 +421,10 @@ return bos; } - /** - * Returns a byte array which contains data special for the given format - * and for the given image data. - */ + /** + * Returns a byte array which contains data special for the given format + * and for the given image data. + */ private native byte[] imageDataToPlatformImageBytes(byte[] imageData, int width, int height, long format); @@ -414,10 +433,8 @@ * Translates either a byte array or an input stream which contain * platform-specific image data in the given format into an Image. */ - protected Image platformImageBytesOrStreamToImage(InputStream str, - byte[] bytes, - long format) - throws IOException { + protected Image platformImageBytesToImage(byte[] bytes, long format) + throws IOException { String mimeType = null; if (format == CF_PNG) { mimeType = "image/png"; @@ -425,11 +442,7 @@ mimeType = "image/jpeg"; } if (mimeType != null) { - return standardImageBytesOrStreamToImage(str, bytes, mimeType); - } - - if (bytes == null) { - bytes = inputStreamToByteArray(str); + return standardImageBytesToImage(bytes, mimeType); } int[] imageData = platformImageBytesToImageData(bytes, format); @@ -443,8 +456,8 @@ DataBufferInt buffer = new DataBufferInt(imageData, len); WritableRaster raster = Raster.createPackedRaster(buffer, width, - height, width, - bandmasks, null); + height, width, + bandmasks, null); return new BufferedImage(directColorModel, raster, false, null); } @@ -457,13 +470,13 @@ */ private native int[] platformImageBytesToImageData(byte[] bytes, long format) - throws IOException; + throws IOException; protected native String[] dragQueryFile(byte[] bytes); } final class WToolkitThreadBlockedHandler extends Mutex - implements ToolkitThreadBlockedHandler { + implements ToolkitThreadBlockedHandler { public void enter() { if (!isOwned()) { @@ -487,7 +500,22 @@ enum EHTMLReadMode { HTML_READ_ALL, HTML_READ_FRAGMENT, - HTML_READ_SELECTION + HTML_READ_SELECTION; + + public static EHTMLReadMode getEHTMLReadMode (DataFlavor df) { + + EHTMLReadMode mode = HTML_READ_SELECTION; + + String parameter = df.getParameter("document"); + + if ("all".equals(parameter)) { + mode = HTML_READ_ALL; + } else if ("fragment".equals(parameter)) { + mode = HTML_READ_FRAGMENT; + } + + return mode; + } } /** @@ -576,26 +604,24 @@ htmlSuffix = "" + htmlSuffix; }; }; - htmlPrefix = htmlPrefix + START_FRAGMENT_CMT; - htmlSuffix = END_FRAGMENT_CMT + htmlSuffix; } String stBaseUrl = DEF_SOURCE_URL; int nStartHTML = - VERSION.length() + VERSION_NUM.length() + EOLN.length() - + START_HTML.length() + PADDED_WIDTH + EOLN.length() - + END_HTML.length() + PADDED_WIDTH + EOLN.length() - + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() - + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() - + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length() - ; + VERSION.length() + VERSION_NUM.length() + EOLN.length() + + START_HTML.length() + PADDED_WIDTH + EOLN.length() + + END_HTML.length() + PADDED_WIDTH + EOLN.length() + + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() + + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length() + + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length() + ; int nStartFragment = nStartHTML + htmlPrefix.length(); int nEndFragment = nStartFragment + bytes.length - 1; int nEndHTML = nEndFragment + htmlSuffix.length(); StringBuilder header = new StringBuilder( - nStartFragment - + START_FRAGMENT_CMT.length() + nStartFragment + + START_FRAGMENT_CMT.length() ); //header header.append(VERSION); @@ -634,14 +660,14 @@ } byte[] retval = new byte[headerBytes.length + bytes.length + - trailerBytes.length]; + trailerBytes.length]; System.arraycopy(headerBytes, 0, retval, 0, headerBytes.length); System.arraycopy(bytes, 0, retval, headerBytes.length, - bytes.length - 1); + bytes.length - 1); System.arraycopy(trailerBytes, 0, retval, - headerBytes.length + bytes.length - 1, - trailerBytes.length); + headerBytes.length + bytes.length - 1, + trailerBytes.length); retval[retval.length-1] = 0; return retval; @@ -654,7 +680,7 @@ private boolean descriptionParsed = false; private boolean closed = false; - // InputStreamReader uses an 8K buffer. The size is not customizable. + // InputStreamReader uses an 8K buffer. The size is not customizable. public static final int BYTE_BUFFER_LEN = 8192; // CharToByteUTF8.getMaxBytesPerChar returns 3, so we should not buffer @@ -662,30 +688,30 @@ public static final int CHAR_BUFFER_LEN = BYTE_BUFFER_LEN / 3; private static final String FAILURE_MSG = - "Unable to parse HTML description: "; + "Unable to parse HTML description: "; private static final String INVALID_MSG = - " invalid"; + " invalid"; //HTML header mapping: private long iHTMLStart,// StartHTML -- shift in array to the first byte after the header - iHTMLEnd, // EndHTML -- shift in array of last byte for HTML syntax analysis - iFragStart,// StartFragment -- shift in array jast after - iFragEnd, // EndFragment -- shift in array before start - iSelStart, // StartSelection -- shift in array of the first char in copied selection - iSelEnd; // EndSelection -- shift in array of the last char in copied selection + iHTMLEnd, // EndHTML -- shift in array of last byte for HTML syntax analysis + iFragStart,// StartFragment -- shift in array jast after + iFragEnd, // EndFragment -- shift in array before start + iSelStart, // StartSelection -- shift in array of the first char in copied selection + iSelEnd; // EndSelection -- shift in array of the last char in copied selection private String stBaseURL; // SourceURL -- base URL for related referenses private String stVersion; // Version -- current supported version //Stream reader markers: private long iStartOffset, - iEndOffset, - iReadCount; + iEndOffset, + iReadCount; private EHTMLReadMode readMode; public HTMLCodec( - InputStream _bytestream, - EHTMLReadMode _readMode) throws IOException + InputStream _bytestream, + EHTMLReadMode _readMode) throws IOException { bufferedStream = new BufferedInputStream(_bytestream, BYTE_BUFFER_LEN); readMode = _readMode; @@ -718,31 +744,31 @@ // initialization of array offset pointers // to the same "uninitialized" state. iHTMLEnd = - iHTMLStart = - iFragEnd = - iFragStart = - iSelEnd = - iSelStart = -1; + iHTMLStart = + iFragEnd = + iFragStart = + iSelEnd = + iSelStart = -1; bufferedStream.mark(BYTE_BUFFER_LEN); String astEntries[] = new String[] { - //common - VERSION, - START_HTML, - END_HTML, - START_FRAGMENT, - END_FRAGMENT, - //ver 1.0 - START_SELECTION, - END_SELECTION, - SOURCE_URL + //common + VERSION, + START_HTML, + END_HTML, + START_FRAGMENT, + END_FRAGMENT, + //ver 1.0 + START_SELECTION, + END_SELECTION, + SOURCE_URL }; BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader( - bufferedStream, - ENCODING - ), - CHAR_BUFFER_LEN + new InputStreamReader( + bufferedStream, + ENCODING + ), + CHAR_BUFFER_LEN ); long iHeadSize = 0; long iCRSize = EOLN.length(); @@ -764,30 +790,30 @@ if( null!=stValue ) { try{ switch( iEntry ){ - case 0: - stVersion = stValue; - break; - case 1: - iHTMLStart = Integer.parseInt(stValue); - break; - case 2: - iHTMLEnd = Integer.parseInt(stValue); - break; - case 3: - iFragStart = Integer.parseInt(stValue); - break; - case 4: - iFragEnd = Integer.parseInt(stValue); - break; - case 5: - iSelStart = Integer.parseInt(stValue); - break; - case 6: - iSelEnd = Integer.parseInt(stValue); - break; - case 7: - stBaseURL = stValue; - break; + case 0: + stVersion = stValue; + break; + case 1: + iHTMLStart = Integer.parseInt(stValue); + break; + case 2: + iHTMLEnd = Integer.parseInt(stValue); + break; + case 3: + iFragStart = Integer.parseInt(stValue); + break; + case 4: + iFragEnd = Integer.parseInt(stValue); + break; + case 5: + iSelStart = Integer.parseInt(stValue); + break; + case 6: + iSelEnd = Integer.parseInt(stValue); + break; + case 7: + stBaseURL = stValue; + break; }; } catch ( NumberFormatException e ) { throw new IOException(FAILURE_MSG + astEntries[iEntry]+ " value " + e + INVALID_MSG); @@ -811,19 +837,19 @@ //one of possible modes switch( readMode ){ - case HTML_READ_ALL: - iStartOffset = iHTMLStart; - iEndOffset = iHTMLEnd; - break; - case HTML_READ_FRAGMENT: - iStartOffset = iFragStart; - iEndOffset = iFragEnd; - break; - case HTML_READ_SELECTION: - default: - iStartOffset = iSelStart; - iEndOffset = iSelEnd; - break; + case HTML_READ_ALL: + iStartOffset = iHTMLStart; + iEndOffset = iHTMLEnd; + break; + case HTML_READ_FRAGMENT: + iStartOffset = iFragStart; + iEndOffset = iFragEnd; + break; + case HTML_READ_SELECTION: + default: + iStartOffset = iSelStart; + iEndOffset = iSelEnd; + break; } bufferedStream.reset();