1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.dnd.ByteArrayTransfer;
14 
15 import org.eclipse.swt.internal.gtk.OS;
16 import org.eclipse.swt.dnd.Transfer;
17 import org.eclipse.swt.dnd.TransferData;
18 import org.eclipse.swt.dnd.DND;
19 import java.lang.all;
20 
21 /**
22  * The class <code>ByteArrayTransfer</code> provides a platform specific
23  * mechanism for converting a java <code>byte[]</code> to a platform
24  * specific representation of the byte array and vice versa.
25  *
26  * <p><code>ByteArrayTransfer</code> is never used directly but is sub-classed
27  * by transfer agents that convert between data in a java format such as a
28  * <code>String</code> and a platform specific byte array.
29  *
30  * <p>If the data you are converting <b>does not</b> map to a
31  * <code>byte[]</code>, you should sub-class <code>Transfer</code> directly
32  * and do your own mapping to a platform data type.</p>
33  *
34  * <p>The following snippet shows a subclass of ByteArrayTransfer that transfers
35  * data defined by the class <code>MyType</code>.</p>
36  *
37  * <pre><code>
38  * public class MyType {
39  *  public String fileName;
40  *  public long fileLength;
41  *  public long lastModified;
42  * }
43  * </code></pre>
44  *
45  * <pre><code>
46  * public class MyTypeTransfer extends ByteArrayTransfer {
47  *
48  *  private static final String MYTYPENAME = "my_type_name";
49  *  private static final int MYTYPEID = registerType(MYTYPENAME);
50  *  private static MyTypeTransfer _instance = new MyTypeTransfer();
51  *
52  * private MyTypeTransfer() {}
53  *
54  * public static MyTypeTransfer getInstance () {
55  *  return _instance;
56  * }
57  * public void javaToNative (Object object, TransferData transferData) {
58  *  if (object is null || !(object instanceof MyType[])) return;
59  *
60  *  if (isSupportedType(transferData)) {
61  *      MyType[] myTypes = (MyType[]) object;
62  *      try {
63  *          // write data to a byte array and then ask super to convert to pMedium
64  *          ByteArrayOutputStream out = new ByteArrayOutputStream();
65  *          DataOutputStream writeOut = new DataOutputStream(out);
66  *          for (int i = 0, length = myTypes.length; i &lt; length;  i++){
67  *              byte[] buffer = myTypes[i].fileName.getBytes();
68  *              writeOut.writeInt(buffer.length);
69  *              writeOut.write(buffer);
70  *              writeOut.writeLong(myTypes[i].fileLength);
71  *              writeOut.writeLong(myTypes[i].lastModified);
72  *          }
73  *          byte[] buffer = out.toByteArray();
74  *          writeOut.close();
75  *
76  *          super.javaToNative(buffer, transferData);
77  *
78  *      } catch (IOException e) {
79  *      }
80  *  }
81  * }
82  * public Object nativeToJava(TransferData transferData){
83  *
84  *  if (isSupportedType(transferData)) {
85  *
86  *      byte[] buffer = (byte[])super.nativeToJava(transferData);
87  *      if (buffer is null) return null;
88  *
89  *      MyType[] myData = new MyType[0];
90  *      try {
91  *          ByteArrayInputStream in = new ByteArrayInputStream(buffer);
92  *          DataInputStream readIn = new DataInputStream(in);
93  *          while(readIn.available() > 20) {
94  *              MyType datum = new MyType();
95  *              int size = readIn.readInt();
96  *              byte[] name = new byte[size];
97  *              readIn.read(name);
98  *              datum.fileName = new String(name);
99  *              datum.fileLength = readIn.readLong();
100  *              datum.lastModified = readIn.readLong();
101  *              MyType[] newMyData = new MyType[myData.length + 1];
102  *              System.arraycopy(myData, 0, newMyData, 0, myData.length);
103  *              newMyData[myData.length] = datum;
104  *              myData = newMyData;
105  *          }
106  *          readIn.close();
107  *      } catch (IOException ex) {
108  *          return null;
109  *      }
110  *      return myData;
111  *  }
112  *
113  *  return null;
114  * }
115  * protected String[] getTypeNames(){
116  *  return new String[]{MYTYPENAME};
117  * }
118  * protected int[] getTypeIds(){
119  *  return new int[] {MYTYPEID};
120  * }
121  * }
122  * </code></pre>
123  *
124  * @see Transfer
125  */
126 public abstract class ByteArrayTransfer : Transfer {
127 
128 public override TransferData[] getSupportedTypes() {
129     int[] types = getTypeIds();
130     TransferData[] data = new TransferData[types.length];
131     for (int i = 0; i < types.length; i++) {
132         data[i] = new TransferData();
133         data[i].type = cast(void*)types[i];
134     }
135     return data;
136 }
137 
138 public override bool isSupportedType(TransferData transferData){
139     if (transferData is null) return false;
140     int[] types = getTypeIds();
141     for (int i = 0; i < types.length; i++) {
142         if (transferData.type is cast(void*)types[i]) return true;
143     }
144     return false;
145 }
146 
147 /**
148  * This implementation of <code>javaToNative</code> converts a java
149  * <code>byte[]</code> to a platform specific representation.
150  * 
151  * @param object a java <code>byte[]</code> containing the data to be converted
152  * @param transferData an empty <code>TransferData</code> object that will
153  *      be filled in on return with the platform specific format of the data
154  * 
155  * @see Transfer#nativeToJava
156  */
157 protected override void javaToNative (Object object, TransferData transferData) {
158     transferData.result = 0;
159     if (!checkByteArray(object) || !isSupportedType(transferData)) {
160         DND.error(DND.ERROR_INVALID_DATA);
161     }
162     byte[] buffer = (cast(ArrayWrapperByte)object).array;
163     if (buffer.length is 0) return;
164     byte* pValue = cast(byte*)OS.g_malloc(buffer.length);
165     if (pValue is null) return;
166     pValue[ 0 .. buffer.length ] = buffer;
167     transferData.length = cast(int)/*64bit*/buffer.length;
168     transferData.format = 8;
169     transferData.pValue = cast(char*)pValue;
170     transferData.result = 1;
171 }
172 
173 /**
174  * This implementation of <code>nativeToJava</code> converts a platform specific
175  * representation of a byte array to a java <code>byte[]</code>.
176  *
177  * @param transferData the platform specific representation of the data to be converted
178  * @return a java <code>byte[]</code> containing the converted data if the conversion was
179  *      successful; otherwise null
180  *
181  * @see Transfer#javaToNative
182  */
183 protected override Object nativeToJava(TransferData transferData) {
184     if ( !isSupportedType(transferData) || transferData.pValue is null) return null;
185     int size = transferData.format * transferData.length / 8;
186     if (size is 0) return null;
187     byte* ptr = cast(byte*)transferData.pValue;
188     return new ArrayWrapperByte( ptr[ 0 .. size ].dup );
189 }
190 
191 bool checkByteArray(Object object) {
192     if( object is null ) return false;
193     ArrayWrapperByte arr = cast(ArrayWrapperByte)object;
194     if( arr is null ) return false;
195     return arr.array.length > 0;
196 }
197 }