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 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_stoc.hxx"
30 
31 #include "stocservices.hxx"
32 
33 #include "supportsService.hxx"
34 
35 #include "com/sun/star/lang/XServiceInfo.hpp"
36 #include "com/sun/star/uno/Exception.hpp"
37 #include "com/sun/star/uno/Reference.hxx"
38 #include "com/sun/star/uno/RuntimeException.hpp"
39 #include "com/sun/star/uno/Sequence.hxx"
40 #include "com/sun/star/uno/XComponentContext.hpp"
41 #include "com/sun/star/uno/XInterface.hpp"
42 #include "com/sun/star/uri/XExternalUriReferenceTranslator.hpp"
43 #include "cppuhelper/implbase2.hxx"
44 #include "cppuhelper/weak.hxx"
45 #include "osl/thread.h"
46 #include "rtl/string.h"
47 #include "rtl/textenc.h"
48 #include "rtl/uri.h"
49 #include "rtl/uri.hxx"
50 #include "rtl/ustrbuf.hxx"
51 #include "rtl/ustring.hxx"
52 #include "sal/types.h"
53 
54 #include <new>
55 
56 namespace css = com::sun::star;
57 
58 namespace {
59 
60 class Translator: public cppu::WeakImplHelper2<
61     css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator >
62 {
63 public:
64     explicit Translator(
65         css::uno::Reference< css::uno::XComponentContext > const & context):
66         m_context(context) {}
67 
68     virtual rtl::OUString SAL_CALL getImplementationName()
69         throw (css::uno::RuntimeException);
70 
71     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
72         throw (css::uno::RuntimeException);
73 
74     virtual css::uno::Sequence< rtl::OUString > SAL_CALL
75     getSupportedServiceNames() throw (css::uno::RuntimeException);
76 
77     virtual rtl::OUString SAL_CALL
78     translateToInternal(rtl::OUString const & externalUriReference)
79         throw (css::uno::RuntimeException);
80 
81     virtual rtl::OUString SAL_CALL
82     translateToExternal(rtl::OUString const & internalUriReference)
83         throw (css::uno::RuntimeException);
84 
85 private:
86     Translator(Translator &); // not implemented
87     void operator =(Translator); // not implemented
88 
89     virtual ~Translator() {}
90 
91     css::uno::Reference< css::uno::XComponentContext > m_context;
92 };
93 
94 rtl::OUString Translator::getImplementationName()
95     throw (css::uno::RuntimeException)
96 {
97     return
98         stoc_services::ExternalUriReferenceTranslator::getImplementationName();
99 }
100 
101 sal_Bool Translator::supportsService(rtl::OUString const & serviceName)
102     throw (css::uno::RuntimeException)
103 {
104     return stoc::uriproc::supportsService(
105         getSupportedServiceNames(), serviceName);
106 }
107 
108 css::uno::Sequence< rtl::OUString > Translator::getSupportedServiceNames()
109     throw (css::uno::RuntimeException)
110 {
111     return stoc_services::ExternalUriReferenceTranslator::
112         getSupportedServiceNames();
113 }
114 
115 rtl::OUString Translator::translateToInternal(
116     rtl::OUString const & externalUriReference)
117     throw (css::uno::RuntimeException)
118 {
119     if (!externalUriReference.matchIgnoreAsciiCaseAsciiL(
120             RTL_CONSTASCII_STRINGPARAM("file:/")))
121     {
122         return externalUriReference;
123     }
124     sal_Int32 i = RTL_CONSTASCII_LENGTH("file:");
125     rtl::OUStringBuffer buf;
126     buf.append(externalUriReference.getStr(), i);
127     // Some environments (e.g., Java) produce illegal file URLs without an
128     // authority part; treat them as having an empty authority part:
129     if (!externalUriReference.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("//"), i))
130     {
131         buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
132     }
133     rtl_TextEncoding encoding = osl_getThreadTextEncoding();
134     for (bool path = true;;) {
135         sal_Int32 j = i;
136         while (j != externalUriReference.getLength()
137                && externalUriReference[j] != '#'
138                && (!path || externalUriReference[j] != '/'))
139         {
140             ++j;
141         }
142         if (j != i) {
143             rtl::OUString seg(
144                 rtl::Uri::encode(
145                     rtl::Uri::decode(
146                         externalUriReference.copy(i, j - i),
147                         rtl_UriDecodeStrict, encoding),
148                     rtl_UriCharClassPchar, rtl_UriEncodeStrict,
149                     RTL_TEXTENCODING_UTF8));
150             if (seg.getLength() == 0) {
151                 return rtl::OUString();
152             }
153             buf.append(seg);
154         }
155         if (j == externalUriReference.getLength()) {
156             break;
157         }
158         buf.append(externalUriReference[j]);
159         path = externalUriReference[j] == '/';
160         i = j + 1;
161     }
162     return buf.makeStringAndClear();
163 }
164 
165 rtl::OUString Translator::translateToExternal(
166     rtl::OUString const & internalUriReference)
167     throw (css::uno::RuntimeException)
168 {
169     if (!internalUriReference.matchIgnoreAsciiCaseAsciiL(
170             RTL_CONSTASCII_STRINGPARAM("file://")))
171     {
172         return internalUriReference;
173     }
174     sal_Int32 i = RTL_CONSTASCII_LENGTH("file://");
175     rtl::OUStringBuffer buf;
176     buf.append(internalUriReference.getStr(), i);
177     rtl_TextEncoding encoding = osl_getThreadTextEncoding();
178     for (bool path = true;;) {
179         sal_Int32 j = i;
180         while (j != internalUriReference.getLength()
181                && internalUriReference[j] != '#'
182                && (!path || internalUriReference[j] != '/'))
183         {
184             ++j;
185         }
186         if (j != i) {
187             // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead
188             // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious
189             // non--UTF-8 octets like "%FE" are copied verbatim:
190             rtl::OUString seg(
191                 rtl::Uri::encode(
192                     rtl::Uri::decode(
193                         internalUriReference.copy(i, j - i),
194                         rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8),
195                     rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes,
196                     encoding));
197             if (seg.getLength() == 0) {
198                 return rtl::OUString();
199             }
200             buf.append(seg);
201         }
202         if (j == internalUriReference.getLength()) {
203             break;
204         }
205         buf.append(internalUriReference[j]);
206         path = internalUriReference[j] == '/';
207         i = j + 1;
208     }
209     return buf.makeStringAndClear();
210 }
211 
212 }
213 
214 namespace stoc_services  { namespace ExternalUriReferenceTranslator {
215 
216 css::uno::Reference< css::uno::XInterface > create(
217     css::uno::Reference< css::uno::XComponentContext > const & context)
218     SAL_THROW((css::uno::Exception))
219 {
220     try {
221         return static_cast< cppu::OWeakObject * >(new Translator(context));
222     } catch (std::bad_alloc &) {
223         throw css::uno::RuntimeException(
224             rtl::OUString::createFromAscii("std::bad_alloc"), 0);
225     }
226 }
227 
228 rtl::OUString getImplementationName() {
229     return rtl::OUString::createFromAscii(
230         "com.sun.star.comp.uri.ExternalUriReferenceTranslator");
231 }
232 
233 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
234     css::uno::Sequence< rtl::OUString > s(1);
235     s[0] = rtl::OUString::createFromAscii(
236         "com.sun.star.uri.ExternalUriReferenceTranslator");
237     return s;
238 }
239 
240 } }
241