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