169 }
170
171 public SortedMap getFormatsForFlavors(DataFlavor[] flavors, FlavorTable map) {
172 SortedMap retval = super.getFormatsForFlavors(flavors, map);
173
174 // The Win32 native code does not support exporting LOCALE data, nor
175 // should it.
176 retval.remove(L_CF_LOCALE);
177
178 return retval;
179 }
180
181 public String getDefaultUnicodeEncoding() {
182 return "utf-16le";
183 }
184
185 public byte[] translateTransferable(Transferable contents,
186 DataFlavor flavor,
187 long format) throws IOException
188 {
189 byte[] bytes = super.translateTransferable(contents, flavor, format);
190
191 if (format == CF_HTML) {
192 bytes = HTMLCodec.convertToHTMLFormat(bytes);
193 }
194 return bytes;
195 }
196
197 protected Object translateBytesOrStream(InputStream str, byte[] bytes,
198 DataFlavor flavor, long format,
199 Transferable localeTransferable)
200 throws IOException
201 {
202 if (format == CF_HTML && flavor.isFlavorTextType()) {
203 if (str == null) {
204 str = new ByteArrayInputStream(bytes);
205 bytes = null;
206 }
207
208 str = new HTMLCodec(str, EHTMLReadMode.HTML_READ_ALL);
209 }
210
211 if (format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW) {
212 if (null != str ) {
213 str.close();
214 }
215 if (bytes == null || !DataFlavor.javaFileListFlavor.equals(flavor)) {
216 throw new IOException("data translation failed");
217 }
218 String st = new String(bytes, 0, bytes.length, "UTF-16LE");
219 String[] filenames = st.split("\0");
220 if( 0 == filenames.length ){
221 return null;
222 }
223
224 // Convert the strings to File objects
225 File[] files = new File[filenames.length];
226 for (int i = 0; i < filenames.length; ++i) {
227 files[i] = new File(filenames[i]);
228 //They are temp-files from memory Stream, so they have to be removed on exit
229 files[i].deleteOnExit();
230 }
231 // Turn the list of Files into a List and return
232 return Arrays.asList(files);
233 }
234
235 if (format == CFSTR_INETURL &&
236 URL.class.equals(flavor.getRepresentationClass()))
237 {
238 if (bytes == null) {
239 bytes = inputStreamToByteArray(str);
240 str = null;
241 }
242 String charset = getDefaultTextCharset();
243 if (localeTransferable != null && localeTransferable.
244 isDataFlavorSupported(javaTextEncodingFlavor))
245 {
246 try {
247 charset = new String((byte[])localeTransferable.
248 getTransferData(javaTextEncodingFlavor),
249 "UTF-8");
250 } catch (UnsupportedFlavorException cannotHappen) {
251 }
252 }
253 return new URL(new String(bytes, charset));
254 }
255
256 return super.translateBytesOrStream(str, bytes, flavor, format,
257 localeTransferable);
258 }
259
260 public boolean isLocaleDependentTextFormat(long format) {
261 return format == CF_TEXT || format == CFSTR_INETURL;
262 }
263
264 public boolean isFileFormat(long format) {
265 return format == CF_HDROP || format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW;
266 }
267
268 protected Long getFormatForNativeAsLong(String str) {
269 Long format = (Long)predefinedClipboardNameMap.get(str);
270 if (format == null) {
271 format = Long.valueOf(registerClipboardFormat(str));
272 }
273 return format;
274 }
275
276 protected String getNativeForFormat(long format) {
277 return (format < predefinedClipboardNames.length)
397 // According to MSDN the byte array have to be double NULL-terminated.
398 // The array contains Unicode characters, so each NULL-terminator is
399 // a pair of bytes
400
401 bos.write(UNICODE_NULL_TERMINATOR);
402 return bos;
403 }
404
405 /**
406 * Returns a byte array which contains data special for the given format
407 * and for the given image data.
408 */
409 private native byte[] imageDataToPlatformImageBytes(byte[] imageData,
410 int width, int height,
411 long format);
412
413 /**
414 * Translates either a byte array or an input stream which contain
415 * platform-specific image data in the given format into an Image.
416 */
417 protected Image platformImageBytesOrStreamToImage(InputStream str,
418 byte[] bytes,
419 long format)
420 throws IOException {
421 String mimeType = null;
422 if (format == CF_PNG) {
423 mimeType = "image/png";
424 } else if (format == CF_JFIF) {
425 mimeType = "image/jpeg";
426 }
427 if (mimeType != null) {
428 return standardImageBytesOrStreamToImage(str, bytes, mimeType);
429 }
430
431 if (bytes == null) {
432 bytes = inputStreamToByteArray(str);
433 }
434
435 int[] imageData = platformImageBytesToImageData(bytes, format);
436 if (imageData == null) {
437 throw new IOException("data translation failed");
438 }
439
440 int len = imageData.length - 2;
441 int width = imageData[len];
442 int height = imageData[len + 1];
443
444 DataBufferInt buffer = new DataBufferInt(imageData, len);
445 WritableRaster raster = Raster.createPackedRaster(buffer, width,
446 height, width,
447 bandmasks, null);
448
449 return new BufferedImage(directColorModel, raster, false, null);
450 }
451
452 /**
470 throw new IllegalMonitorStateException();
471 }
472 unlock();
473 startSecondaryEventLoop();
474 lock();
475 }
476
477 public void exit() {
478 if (!isOwned()) {
479 throw new IllegalMonitorStateException();
480 }
481 WToolkit.quitSecondaryEventLoop();
482 }
483
484 private native void startSecondaryEventLoop();
485 }
486
487 enum EHTMLReadMode {
488 HTML_READ_ALL,
489 HTML_READ_FRAGMENT,
490 HTML_READ_SELECTION
491 }
492
493 /**
494 * on decode: This stream takes an InputStream which provides data in CF_HTML format,
495 * strips off the description and context to extract the original HTML data.
496 *
497 * on encode: static convertToHTMLFormat is responsible for HTML clipboard header creation
498 */
499 class HTMLCodec extends InputStream {
500 //static section
501 public static final String ENCODING = "UTF-8";
502
503 public static final String VERSION = "Version:";
504 public static final String START_HTML = "StartHTML:";
505 public static final String END_HTML = "EndHTML:";
506 public static final String START_FRAGMENT = "StartFragment:";
507 public static final String END_FRAGMENT = "EndFragment:";
508 public static final String START_SELECTION = "StartSelection:"; //optional
509 public static final String END_SELECTION = "EndSelection:"; //optional
510
559 *<HTML>...<!--StartFragment-->...<BODY>...</BODY><!--EndFragment--><HTML>
560 * are vailid too.
561 */
562 public static byte[] convertToHTMLFormat(byte[] bytes) {
563 // Calculate section offsets
564 String htmlPrefix = "";
565 String htmlSuffix = "";
566 {
567 //we have extend the fragment to full HTML document correctly
568 //to avoid HTML and BODY tags doubling
569 String stContext = new String(bytes);
570 String stUpContext = stContext.toUpperCase();
571 if( -1 == stUpContext.indexOf("<HTML") ) {
572 htmlPrefix = "<HTML>";
573 htmlSuffix = "</HTML>";
574 if( -1 == stUpContext.indexOf("<BODY") ) {
575 htmlPrefix = htmlPrefix +"<BODY>";
576 htmlSuffix = "</BODY>" + htmlSuffix;
577 };
578 };
579 htmlPrefix = htmlPrefix + START_FRAGMENT_CMT;
580 htmlSuffix = END_FRAGMENT_CMT + htmlSuffix;
581 }
582
583 String stBaseUrl = DEF_SOURCE_URL;
584 int nStartHTML =
585 VERSION.length() + VERSION_NUM.length() + EOLN.length()
586 + START_HTML.length() + PADDED_WIDTH + EOLN.length()
587 + END_HTML.length() + PADDED_WIDTH + EOLN.length()
588 + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
589 + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
590 + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length()
591 ;
592 int nStartFragment = nStartHTML + htmlPrefix.length();
593 int nEndFragment = nStartFragment + bytes.length - 1;
594 int nEndHTML = nEndFragment + htmlSuffix.length();
595
596 StringBuilder header = new StringBuilder(
597 nStartFragment
598 + START_FRAGMENT_CMT.length()
599 );
600 //header
|
169 }
170
171 public SortedMap getFormatsForFlavors(DataFlavor[] flavors, FlavorTable map) {
172 SortedMap retval = super.getFormatsForFlavors(flavors, map);
173
174 // The Win32 native code does not support exporting LOCALE data, nor
175 // should it.
176 retval.remove(L_CF_LOCALE);
177
178 return retval;
179 }
180
181 public String getDefaultUnicodeEncoding() {
182 return "utf-16le";
183 }
184
185 public byte[] translateTransferable(Transferable contents,
186 DataFlavor flavor,
187 long format) throws IOException
188 {
189 byte[] bytes = null;
190 if (format == CF_HTML) {
191 if (contents.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor)) {
192 // if a user provides data represented by
193 // DataFlavor.selectionHtmlFlavor format, we use this
194 // type to store the data in the native clipboard
195 bytes = super.translateTransferable(contents,
196 DataFlavor.selectionHtmlFlavor,
197 format);
198 } else if (contents.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) {
199 // if we cannot get data represented by the
200 // DataFlavor.selectionHtmlFlavor format
201 // but the DataFlavor.allHtmlFlavor format is avialable
202 // we belive that the user knows how to represent
203 // the data and how to mark up selection in a
204 // system specific manner. Therefor, we use this data
205 bytes = super.translateTransferable(contents,
206 DataFlavor.allHtmlFlavor,
207 format);
208 } else {
209 // handle other html flavor types, including custom and
210 // fragment ones
211 bytes = HTMLCodec.convertToHTMLFormat(super.translateTransferable(contents, flavor, format));
212 }
213 } else {
214 // we handle non-html types basing on their
215 // flavors
216 bytes = super.translateTransferable(contents, flavor, format);
217 }
218 return bytes;
219 }
220
221 // The stream is closed as a closable object
222 public Object translateStream(InputStream str,
223 DataFlavor flavor, long format,
224 Transferable localeTransferable)
225 throws IOException {
226 if (format == CF_HTML && flavor.isFlavorTextType()) {
227 str = new HTMLCodec(str,
228 EHTMLReadMode.getEHTMLReadMode(flavor));
229
230 }
231 return super.translateStream(str, flavor, format,
232 localeTransferable);
233 }
234
235 public Object translateBytes(byte[] bytes, DataFlavor flavor, long format,
236 Transferable localeTransferable) throws IOException {
237
238 if (format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW) {
239 if (bytes == null || !DataFlavor.javaFileListFlavor.equals(flavor)) {
240 throw new IOException("data translation failed");
241 }
242 String st = new String(bytes, 0, bytes.length, "UTF-16LE");
243 String[] filenames = st.split("\0");
244 if( 0 == filenames.length ){
245 return null;
246 }
247
248 // Convert the strings to File objects
249 File[] files = new File[filenames.length];
250 for (int i = 0; i < filenames.length; ++i) {
251 files[i] = new File(filenames[i]);
252 //They are temp-files from memory Stream, so they have to be removed on exit
253 files[i].deleteOnExit();
254 }
255 // Turn the list of Files into a List and return
256 return Arrays.asList(files);
257 }
258
259 if (format == CFSTR_INETURL &&
260 URL.class.equals(flavor.getRepresentationClass()))
261 {
262 String charset = getDefaultTextCharset();
263 if (localeTransferable != null && localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor))
264 {
265 try {
266 charset = new String((byte[])localeTransferable.
267 getTransferData(javaTextEncodingFlavor), "UTF-8");
268 } catch (UnsupportedFlavorException cannotHappen) {
269 }
270 }
271 return new URL(new String(bytes, charset));
272 }
273
274 return super.translateBytes(bytes , flavor, format,
275 localeTransferable);
276
277 }
278
279 public boolean isLocaleDependentTextFormat(long format) {
280 return format == CF_TEXT || format == CFSTR_INETURL;
281 }
282
283 public boolean isFileFormat(long format) {
284 return format == CF_HDROP || format == CF_FILEGROUPDESCRIPTORA || format == CF_FILEGROUPDESCRIPTORW;
285 }
286
287 protected Long getFormatForNativeAsLong(String str) {
288 Long format = (Long)predefinedClipboardNameMap.get(str);
289 if (format == null) {
290 format = Long.valueOf(registerClipboardFormat(str));
291 }
292 return format;
293 }
294
295 protected String getNativeForFormat(long format) {
296 return (format < predefinedClipboardNames.length)
416 // According to MSDN the byte array have to be double NULL-terminated.
417 // The array contains Unicode characters, so each NULL-terminator is
418 // a pair of bytes
419
420 bos.write(UNICODE_NULL_TERMINATOR);
421 return bos;
422 }
423
424 /**
425 * Returns a byte array which contains data special for the given format
426 * and for the given image data.
427 */
428 private native byte[] imageDataToPlatformImageBytes(byte[] imageData,
429 int width, int height,
430 long format);
431
432 /**
433 * Translates either a byte array or an input stream which contain
434 * platform-specific image data in the given format into an Image.
435 */
436 protected Image platformImageBytesToImage(byte[] bytes, long format)
437 throws IOException {
438 String mimeType = null;
439 if (format == CF_PNG) {
440 mimeType = "image/png";
441 } else if (format == CF_JFIF) {
442 mimeType = "image/jpeg";
443 }
444 if (mimeType != null) {
445 return standardImageBytesToImage(bytes, mimeType);
446 }
447
448 int[] imageData = platformImageBytesToImageData(bytes, format);
449 if (imageData == null) {
450 throw new IOException("data translation failed");
451 }
452
453 int len = imageData.length - 2;
454 int width = imageData[len];
455 int height = imageData[len + 1];
456
457 DataBufferInt buffer = new DataBufferInt(imageData, len);
458 WritableRaster raster = Raster.createPackedRaster(buffer, width,
459 height, width,
460 bandmasks, null);
461
462 return new BufferedImage(directColorModel, raster, false, null);
463 }
464
465 /**
483 throw new IllegalMonitorStateException();
484 }
485 unlock();
486 startSecondaryEventLoop();
487 lock();
488 }
489
490 public void exit() {
491 if (!isOwned()) {
492 throw new IllegalMonitorStateException();
493 }
494 WToolkit.quitSecondaryEventLoop();
495 }
496
497 private native void startSecondaryEventLoop();
498 }
499
500 enum EHTMLReadMode {
501 HTML_READ_ALL,
502 HTML_READ_FRAGMENT,
503 HTML_READ_SELECTION;
504
505 public static EHTMLReadMode getEHTMLReadMode (DataFlavor df) {
506
507 EHTMLReadMode mode = HTML_READ_SELECTION;
508
509 String parameter = df.getParameter("document");
510
511 if ("all".equals(parameter)) {
512 mode = HTML_READ_ALL;
513 } else if ("fragment".equals(parameter)) {
514 mode = HTML_READ_FRAGMENT;
515 }
516
517 return mode;
518 }
519 }
520
521 /**
522 * on decode: This stream takes an InputStream which provides data in CF_HTML format,
523 * strips off the description and context to extract the original HTML data.
524 *
525 * on encode: static convertToHTMLFormat is responsible for HTML clipboard header creation
526 */
527 class HTMLCodec extends InputStream {
528 //static section
529 public static final String ENCODING = "UTF-8";
530
531 public static final String VERSION = "Version:";
532 public static final String START_HTML = "StartHTML:";
533 public static final String END_HTML = "EndHTML:";
534 public static final String START_FRAGMENT = "StartFragment:";
535 public static final String END_FRAGMENT = "EndFragment:";
536 public static final String START_SELECTION = "StartSelection:"; //optional
537 public static final String END_SELECTION = "EndSelection:"; //optional
538
587 *<HTML>...<!--StartFragment-->...<BODY>...</BODY><!--EndFragment--><HTML>
588 * are vailid too.
589 */
590 public static byte[] convertToHTMLFormat(byte[] bytes) {
591 // Calculate section offsets
592 String htmlPrefix = "";
593 String htmlSuffix = "";
594 {
595 //we have extend the fragment to full HTML document correctly
596 //to avoid HTML and BODY tags doubling
597 String stContext = new String(bytes);
598 String stUpContext = stContext.toUpperCase();
599 if( -1 == stUpContext.indexOf("<HTML") ) {
600 htmlPrefix = "<HTML>";
601 htmlSuffix = "</HTML>";
602 if( -1 == stUpContext.indexOf("<BODY") ) {
603 htmlPrefix = htmlPrefix +"<BODY>";
604 htmlSuffix = "</BODY>" + htmlSuffix;
605 };
606 };
607 }
608
609 String stBaseUrl = DEF_SOURCE_URL;
610 int nStartHTML =
611 VERSION.length() + VERSION_NUM.length() + EOLN.length()
612 + START_HTML.length() + PADDED_WIDTH + EOLN.length()
613 + END_HTML.length() + PADDED_WIDTH + EOLN.length()
614 + START_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
615 + END_FRAGMENT.length() + PADDED_WIDTH + EOLN.length()
616 + SOURCE_URL.length() + stBaseUrl.length() + EOLN.length()
617 ;
618 int nStartFragment = nStartHTML + htmlPrefix.length();
619 int nEndFragment = nStartFragment + bytes.length - 1;
620 int nEndHTML = nEndFragment + htmlSuffix.length();
621
622 StringBuilder header = new StringBuilder(
623 nStartFragment
624 + START_FRAGMENT_CMT.length()
625 );
626 //header
|