001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Pavel Dolgov
019: * @version $Revision$
020: */package org.apache.harmony.awt.datatransfer;
021:
022: import java.awt.Image;
023: import java.awt.Transparency;
024: import java.awt.color.ColorSpace;
025: import java.awt.datatransfer.DataFlavor;
026: import java.awt.datatransfer.SystemFlavorMap;
027: import java.awt.datatransfer.Transferable;
028: import java.awt.datatransfer.UnsupportedFlavorException;
029: import java.awt.image.BufferedImage;
030: import java.awt.image.ColorModel;
031: import java.awt.image.ComponentColorModel;
032: import java.awt.image.DataBuffer;
033: import java.awt.image.DataBufferByte;
034: import java.awt.image.DataBufferInt;
035: import java.awt.image.DataBufferUShort;
036: import java.awt.image.DirectColorModel;
037: import java.awt.image.Raster;
038: import java.awt.image.WritableRaster;
039: import java.io.ByteArrayInputStream;
040: import java.io.IOException;
041: import java.io.InputStream;
042: import java.io.ObjectInputStream;
043: import java.io.Reader;
044: import java.io.StringReader;
045: import java.net.URL;
046: import java.nio.ByteBuffer;
047: import java.nio.CharBuffer;
048: import java.util.ArrayList;
049: import java.util.Arrays;
050: import java.util.Iterator;
051: import java.util.List;
052:
053: import org.apache.harmony.awt.internal.nls.Messages;
054:
055: /**
056: * Wrapper for native data
057: */
058: public final class DataProxy implements Transferable {
059:
060: public static final Class[] unicodeTextClasses = { String.class,
061: Reader.class, CharBuffer.class, char[].class };
062: public static final Class[] charsetTextClasses = { byte[].class,
063: ByteBuffer.class, InputStream.class };
064:
065: private final DataProvider data;
066: private final SystemFlavorMap flavorMap;
067:
068: public DataProxy(DataProvider data) {
069: this .data = data;
070: this .flavorMap = (SystemFlavorMap) SystemFlavorMap
071: .getDefaultFlavorMap();
072: }
073:
074: public DataProvider getDataProvider() {
075: return data;
076: }
077:
078: public Object getTransferData(DataFlavor flavor)
079: throws UnsupportedFlavorException, IOException {
080:
081: String mimeType = flavor.getPrimaryType()
082: + "/" + flavor.getSubType(); //$NON-NLS-1$
083: if (flavor.isFlavorTextType()) {
084: if (mimeType.equalsIgnoreCase(DataProvider.TYPE_HTML)) {
085: return getHTML(flavor);
086: }
087: if (mimeType.equalsIgnoreCase(DataProvider.TYPE_URILIST)) {
088: return getURL(flavor);
089: }
090: return getPlainText(flavor);
091: }
092: if (flavor.isFlavorJavaFileListType()) {
093: return getFileList(flavor);
094: }
095: if (flavor.isFlavorSerializedObjectType()) {
096: return getSerializedObject(flavor);
097: }
098: if (flavor.equals(DataProvider.urlFlavor)) {
099: return getURL(flavor);
100: }
101: if (mimeType.equalsIgnoreCase(DataProvider.TYPE_IMAGE)
102: && Image.class.isAssignableFrom(flavor
103: .getRepresentationClass())) {
104: return getImage(flavor);
105: }
106:
107: throw new UnsupportedFlavorException(flavor);
108: }
109:
110: public DataFlavor[] getTransferDataFlavors() {
111: ArrayList<DataFlavor> result = new ArrayList<DataFlavor>();
112: String[] natives = data.getNativeFormats();
113:
114: for (int i = 0; i < natives.length; i++) {
115: List<DataFlavor> flavors = flavorMap
116: .getFlavorsForNative(natives[i]);
117: for (Iterator<DataFlavor> it = flavors.iterator(); it
118: .hasNext();) {
119: DataFlavor f = it.next();
120: if (!result.contains(f)) {
121: result.add(f);
122: }
123: }
124: }
125: return result.toArray(new DataFlavor[result.size()]);
126: }
127:
128: public boolean isDataFlavorSupported(DataFlavor flavor) {
129: DataFlavor[] flavors = getTransferDataFlavors();
130: for (int i = 0; i < flavors.length; i++) {
131: if (flavors[i].equals(flavor)) {
132: return true;
133: }
134: }
135: return false;
136: }
137:
138: private Object getPlainText(DataFlavor f) throws IOException,
139: UnsupportedFlavorException {
140: if (!data.isNativeFormatAvailable(DataProvider.FORMAT_TEXT)) {
141: throw new UnsupportedFlavorException(f);
142: }
143: String str = data.getText();
144: if (str == null) {
145: // awt.4F=Data is not available
146: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
147: }
148: return getTextRepresentation(str, f);
149: }
150:
151: private Object getFileList(DataFlavor f) throws IOException,
152: UnsupportedFlavorException {
153: if (!data
154: .isNativeFormatAvailable(DataProvider.FORMAT_FILE_LIST)) {
155: throw new UnsupportedFlavorException(f);
156: }
157: String[] files = data.getFileList();
158: if (files == null) {
159: // awt.4F=Data is not available
160: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
161: }
162: return Arrays.asList(files);
163: }
164:
165: private Object getHTML(DataFlavor f) throws IOException,
166: UnsupportedFlavorException {
167: if (!data.isNativeFormatAvailable(DataProvider.FORMAT_HTML)) {
168: throw new UnsupportedFlavorException(f);
169: }
170: String str = data.getHTML();
171: if (str == null) {
172: // awt.4F=Data is not available
173: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
174: }
175: return getTextRepresentation(str, f);
176: }
177:
178: private Object getURL(DataFlavor f) throws IOException,
179: UnsupportedFlavorException {
180: if (!data.isNativeFormatAvailable(DataProvider.FORMAT_URL)) {
181: throw new UnsupportedFlavorException(f);
182: }
183: String str = data.getURL();
184: if (str == null) {
185: // awt.4F=Data is not available
186: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
187: }
188: URL url = new URL(str);
189: if (f.getRepresentationClass().isAssignableFrom(URL.class)) {
190: return url;
191: }
192: if (f.isFlavorTextType()) {
193: return getTextRepresentation(url.toString(), f);
194: }
195: throw new UnsupportedFlavorException(f);
196: }
197:
198: private Object getSerializedObject(DataFlavor f)
199: throws IOException, UnsupportedFlavorException {
200: String nativeFormat = SystemFlavorMap.encodeDataFlavor(f);
201: if ((nativeFormat == null)
202: || !data.isNativeFormatAvailable(nativeFormat)) {
203: throw new UnsupportedFlavorException(f);
204: }
205: byte bytes[] = data.getSerializedObject(f
206: .getRepresentationClass());
207: if (bytes == null) {
208: // awt.4F=Data is not available
209: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
210: }
211: ByteArrayInputStream str = new ByteArrayInputStream(bytes);
212: try {
213: return new ObjectInputStream(str).readObject();
214: } catch (ClassNotFoundException ex) {
215: throw new IOException(ex.getMessage());
216: }
217: }
218:
219: private String getCharset(DataFlavor f) {
220: return f.getParameter("charset"); //$NON-NLS-1$
221: }
222:
223: private Object getTextRepresentation(String text, DataFlavor f)
224: throws UnsupportedFlavorException, IOException {
225: if (f.getRepresentationClass() == String.class) {
226: return text;
227: }
228: if (f.isRepresentationClassReader()) {
229: return new StringReader(text);
230: }
231: if (f.isRepresentationClassCharBuffer()) {
232: return CharBuffer.wrap(text);
233: }
234: if (f.getRepresentationClass() == char[].class) {
235: char[] chars = new char[text.length()];
236: text.getChars(0, text.length(), chars, 0);
237: return chars;
238: }
239: String charset = getCharset(f);
240: if (f.getRepresentationClass() == byte[].class) {
241: byte[] bytes = text.getBytes(charset);
242: return bytes;
243: }
244: if (f.isRepresentationClassByteBuffer()) {
245: byte[] bytes = text.getBytes(charset);
246: return ByteBuffer.wrap(bytes);
247: }
248: if (f.isRepresentationClassInputStream()) {
249: byte[] bytes = text.getBytes(charset);
250: return new ByteArrayInputStream(bytes);
251: }
252: throw new UnsupportedFlavorException(f);
253: }
254:
255: private Image getImage(DataFlavor f) throws IOException,
256: UnsupportedFlavorException {
257: if (!data.isNativeFormatAvailable(DataProvider.FORMAT_IMAGE)) {
258: throw new UnsupportedFlavorException(f);
259: }
260: RawBitmap bitmap = data.getRawBitmap();
261: if (bitmap == null) {
262: // awt.4F=Data is not available
263: throw new IOException(Messages.getString("awt.4F")); //$NON-NLS-1$
264: }
265: return createBufferedImage(bitmap);
266: }
267:
268: private boolean isRGB(RawBitmap b) {
269: return b.rMask == 0xFF0000 && b.gMask == 0xFF00
270: && b.bMask == 0xFF;
271: }
272:
273: private boolean isBGR(RawBitmap b) {
274: return b.rMask == 0xFF && b.gMask == 0xFF00
275: && b.bMask == 0xFF0000;
276: }
277:
278: private BufferedImage createBufferedImage(RawBitmap b) {
279: if (b == null || b.buffer == null || b.width <= 0
280: || b.height <= 0) {
281: return null;
282: }
283:
284: ColorModel cm = null;
285: WritableRaster wr = null;
286:
287: if (b.bits == 32 && b.buffer instanceof int[]) {
288: if (!isRGB(b) && !isBGR(b)) {
289: return null;
290: }
291: int masks[] = { b.rMask, b.gMask, b.bMask };
292: int buffer[] = (int[]) b.buffer;
293: cm = new DirectColorModel(24, b.rMask, b.gMask, b.bMask);
294: wr = Raster.createPackedRaster(new DataBufferInt(buffer,
295: buffer.length), b.width, b.height, b.stride, masks,
296: null);
297:
298: } else if (b.bits == 24 && b.buffer instanceof byte[]) {
299: int bits[] = { 8, 8, 8 };
300: int offsets[];
301: if (isRGB(b)) {
302: offsets = new int[] { 0, 1, 2 };
303: } else if (isBGR(b)) {
304: offsets = new int[] { 2, 1, 0 };
305: } else {
306: return null;
307: }
308: byte buffer[] = (byte[]) b.buffer;
309: cm = new ComponentColorModel(ColorSpace
310: .getInstance(ColorSpace.CS_sRGB), bits, false,
311: false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
312:
313: wr = Raster.createInterleavedRaster(new DataBufferByte(
314: buffer, buffer.length), b.width, b.height,
315: b.stride, 3, offsets, null);
316:
317: } else if ((b.bits == 16 || b.bits == 15)
318: && b.buffer instanceof short[]) {
319: int masks[] = { b.rMask, b.gMask, b.bMask };
320: short buffer[] = (short[]) b.buffer;
321: cm = new DirectColorModel(b.bits, b.rMask, b.gMask, b.bMask);
322: wr = Raster.createPackedRaster(new DataBufferUShort(buffer,
323: buffer.length), b.width, b.height, b.stride, masks,
324: null);
325: }
326:
327: if (cm == null || wr == null) {
328: return null;
329: }
330: return new BufferedImage(cm, wr, false, null);
331: }
332: }
|