1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 package com.sun.star.lib.util; 28 29 import java.io.File; 30 import java.lang.reflect.Constructor; 31 import java.lang.reflect.InvocationTargetException; 32 import java.lang.reflect.Method; 33 import java.net.URL; 34 import java.net.URLDecoder; 35 import java.net.URLEncoder; 36 37 /** 38 * Maps Java URL representations to File representations, on any Java version. 39 * 40 * @since UDK 3.2.8 41 */ 42 public final class UrlToFileMapper { 43 44 // java.net.URLEncoder.encode(String, String) and java.net.URI are only 45 // available since Java 1.4: 46 private static Method urlEncoderEncode; 47 private static Constructor uriConstructor; 48 private static Constructor fileConstructor; 49 static { 50 try { 51 urlEncoderEncode = URLEncoder.class.getMethod( 52 "encode", new Class[] { String.class, String.class }); 53 Class uriClass = Class.forName("java.net.URI"); 54 uriConstructor = uriClass.getConstructor( 55 new Class[] { String.class }); 56 fileConstructor = File.class.getConstructor( 57 new Class[] { uriClass }); 58 } catch (ClassNotFoundException e) { 59 } catch (NoSuchMethodException e) { 60 } 61 } 62 63 /** 64 * Maps Java URL representations to File representations. 65 * 66 * @param url some URL, possibly null. 67 * @return a corresponding File, or null on failure. 68 */ 69 public static File mapUrlToFile(URL url) { 70 if (url == null) { 71 return null; 72 } else if (fileConstructor == null) { 73 // If java.net.URI is not available, hope that the following works 74 // well: First, check that the given URL has a certain form. 75 // Second, use the URLDecoder to decode the URL path (taking care 76 // not to change any plus signs to spaces), hoping that the used 77 // default encoding is the proper one for file URLs. Third, create 78 // a File from the decoded path. 79 return url.getProtocol().equalsIgnoreCase("file") 80 && url.getAuthority() == null && url.getQuery() == null 81 && url.getRef() == null 82 ? new File(URLDecoder.decode( 83 StringHelper.replace(url.getPath(), '+', "%2B"))) 84 : null; 85 } else { 86 // If java.net.URI is avaliable, do 87 // URI uri = new URI(encodedUrl); 88 // try { 89 // return new File(uri); 90 // } catch (IllegalArgumentException e) { 91 // return null; 92 // } 93 // where encodedUrl is url.toString(), but since that may contain 94 // unsafe characters (e.g., space, " "), it is encoded, as otherwise 95 // the URI constructor might throw java.net.URISyntaxException (in 96 // Java 1.5, URL.toURI might be used instead). 97 String encodedUrl = encode(url.toString()); 98 try { 99 Object uri = uriConstructor.newInstance( 100 new Object[] { encodedUrl }); 101 try { 102 return (File) fileConstructor.newInstance( 103 new Object[] { uri }); 104 } catch (InvocationTargetException e) { 105 if (e.getTargetException() instanceof 106 IllegalArgumentException) { 107 return null; 108 } else { 109 throw e; 110 } 111 } 112 } catch (InstantiationException e) { 113 throw new RuntimeException("This cannot happen: " + e); 114 } catch (IllegalAccessException e) { 115 throw new RuntimeException("This cannot happen: " + e); 116 } catch (InvocationTargetException e) { 117 if (e.getTargetException() instanceof Error) { 118 throw (Error) e.getTargetException(); 119 } else if (e.getTargetException() instanceof RuntimeException) { 120 throw (RuntimeException) e.getTargetException(); 121 } else { 122 throw new RuntimeException("This cannot happen: " + e); 123 } 124 } 125 } 126 } 127 128 129 130 private static String encode(String url) { 131 StringBuffer buf = new StringBuffer(); 132 for (int i = 0; i < url.length(); ++i) { 133 char c = url.charAt(i); 134 // The RFC 2732 <uric> characters: !$&'()*+,-./:;=?@[]_~ plus digits 135 // and letters; additionally, do not encode % again. 136 if (c >= 'a' && c <= 'z' || c >= '?' && c <= '[' 137 || c >= '$' && c <= ';' || c == '!' || c == '=' || c == ']' 138 || c == '_' || c == '~') 139 { 140 buf.append(c); 141 } else if (c == ' ') { 142 buf.append("%20"); 143 } else { 144 String enc; 145 try { 146 enc = (String) urlEncoderEncode.invoke( 147 null, 148 new Object[] {Character.toString(c), "UTF-8" }); 149 } catch (IllegalAccessException e) { 150 throw new RuntimeException("This cannot happen: " + e); 151 } catch (InvocationTargetException e) { 152 throw new RuntimeException("This cannot happen: " + e); 153 } 154 buf.append(enc); 155 } 156 } 157 return buf.toString(); 158 } 159 160 private UrlToFileMapper() {} 161 } 162