xref: /trunk/main/ucb/source/ucp/package/pkguri.cxx (revision cdf0e10c)
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_ucb.hxx"
30 
31 /**************************************************************************
32                                 TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 
37 #include "rtl/ustrbuf.hxx"
38 #include "osl/diagnose.h"
39 #include "comphelper/storagehelper.hxx"
40 
41 #include "../inc/urihelper.hxx"
42 
43 #include "pkguri.hxx"
44 
45 using namespace package_ucp;
46 using namespace rtl;
47 
48 //=========================================================================
49 //=========================================================================
50 //
51 // PackageUri Implementation.
52 //
53 //=========================================================================
54 //=========================================================================
55 
56 static void normalize( OUString& rURL )
57 {
58     sal_Int32 nPos = 0;
59     do
60     {
61         nPos = rURL.indexOf( '%', nPos );
62         if ( nPos != -1 )
63         {
64             if ( nPos < ( rURL.getLength() - 2 ) )
65             {
66                 OUString aTmp = rURL.copy( nPos + 1, 2 );
67                 rURL = rURL.replaceAt( nPos + 1, 2, aTmp.toAsciiUpperCase() );
68                 nPos++;
69             }
70         }
71     }
72     while ( nPos != -1 );
73 }
74 
75 //=========================================================================
76 void PackageUri::init() const
77 {
78     // Already inited?
79     if ( m_aUri.getLength() && !m_aPath.getLength() )
80     {
81         // Note: Maybe it's a re-init, setUri only resets m_aPath!
82         m_aPackage = m_aParentUri = m_aName = m_aParam = m_aScheme
83             = OUString();
84 
85         // URI must match at least: <sheme>://<non_empty_url_to_file>
86         if ( ( m_aUri.getLength() < PACKAGE_URL_SCHEME_LENGTH + 4 ) )
87         {
88             // error, but remember that we did a init().
89             m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
90             return;
91         }
92 
93         // Scheme must be followed by '://'
94         if ( ( m_aUri.getStr()[ PACKAGE_URL_SCHEME_LENGTH ]
95                 != sal_Unicode( ':' ) )
96              ||
97              ( m_aUri.getStr()[ PACKAGE_URL_SCHEME_LENGTH + 1 ]
98                 != sal_Unicode( '/' ) )
99              ||
100              ( m_aUri.getStr()[ PACKAGE_URL_SCHEME_LENGTH + 2 ]
101                 != sal_Unicode( '/' ) ) )
102         {
103             // error, but remember that we did a init().
104             m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
105             return;
106         }
107 
108 		rtl::OUString aPureUri;
109 		sal_Int32 nParam = m_aUri.indexOf( '?' );
110 		if( nParam >= 0 )
111 		{
112 			m_aParam = m_aUri.copy( nParam );
113 			aPureUri = m_aUri.copy( 0, nParam );
114 		}
115 		else
116 			aPureUri = m_aUri;
117 
118         // Scheme is case insensitive.
119         m_aScheme = aPureUri.copy(
120             0, PACKAGE_URL_SCHEME_LENGTH ).toAsciiLowerCase();
121 
122         if ( m_aScheme.equalsAsciiL(
123                  RTL_CONSTASCII_STRINGPARAM( PACKAGE_URL_SCHEME ) )
124           || m_aScheme.equalsAsciiL(
125               RTL_CONSTASCII_STRINGPARAM( PACKAGE_ZIP_URL_SCHEME ) ) )
126         {
127         	if ( m_aScheme.equalsAsciiL(
128                      RTL_CONSTASCII_STRINGPARAM( PACKAGE_ZIP_URL_SCHEME ) ) )
129 			{
130 				m_aParam +=
131                     ( m_aParam.getLength()
132                       ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&purezip" ) )
133                       : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "?purezip" ) ) );
134 			}
135 
136             aPureUri = aPureUri.replaceAt( 0,
137                                            m_aScheme.getLength(),
138                                            m_aScheme );
139 
140             sal_Int32 nStart = PACKAGE_URL_SCHEME_LENGTH + 3;
141             sal_Int32 nEnd   = aPureUri.lastIndexOf( '/' );
142             if ( nEnd == PACKAGE_URL_SCHEME_LENGTH + 3 )
143             {
144                 // Only <scheme>:/// - Empty authority
145 
146                 // error, but remember that we did a init().
147                 m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
148                 return;
149             }
150             else if ( nEnd == ( aPureUri.getLength() - 1 ) )
151             {
152                 if ( aPureUri.getStr()[ aPureUri.getLength() - 2 ]
153                                                 == sal_Unicode( '/' ) )
154                 {
155                     // Only <scheme>://// or <scheme>://<something>//
156 
157                     // error, but remember that we did a init().
158                     m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
159                     return;
160                 }
161 
162                 // Remove trailing slash.
163                 aPureUri = aPureUri.copy( 0, nEnd );
164             }
165 
166 
167             nEnd = aPureUri.indexOf( '/', nStart );
168             if ( nEnd == -1 )
169             {
170                 // root folder.
171 
172                 OUString aNormPackage = aPureUri.copy( nStart );
173                 normalize( aNormPackage );
174 
175                 aPureUri = aPureUri.replaceAt(
176                     nStart, aPureUri.getLength() - nStart, aNormPackage );
177                 m_aPackage
178                     = ::ucb_impl::urihelper::decodeSegment( aNormPackage );
179                 m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
180 				m_aUri = m_aUri.replaceAt( 0,
181                                            ( nParam >= 0 )
182                                            ? nParam
183                                            : m_aUri.getLength(), aPureUri );
184 
185                 sal_Int32 nLastSlash = m_aPackage.lastIndexOf( '/' );
186                 if ( nLastSlash != -1 )
187                     m_aName = ::ucb_impl::urihelper::decodeSegment(
188                         m_aPackage.copy( nLastSlash + 1 ) );
189                 else
190                     m_aName
191                         = ::ucb_impl::urihelper::decodeSegment( m_aPackage );
192             }
193             else
194             {
195                 m_aPath = aPureUri.copy( nEnd + 1 );
196 
197                 // Unexpected sequences of characters:
198                 // - empty path segments
199                 // - encoded slashes
200                 // - parent folder segments ".."
201                 // - current folder segments "."
202                 if ( m_aPath.indexOf( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "//" ) ) ) != -1
203                   || m_aPath.indexOf( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "%2F" ) ) ) != -1
204                   || m_aPath.indexOf( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "%2f" ) ) ) != -1
205                   || ::comphelper::OStorageHelper::PathHasSegment( m_aPath, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".." ) ) )
206                   || ::comphelper::OStorageHelper::PathHasSegment( m_aPath, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) ) )
207                 {
208                     // error, but remember that we did a init().
209                     m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
210                     return;
211                 }
212 
213                 OUString aNormPackage = aPureUri.copy( nStart, nEnd - nStart );
214                 normalize( aNormPackage );
215 
216                 aPureUri = aPureUri.replaceAt(
217                     nStart, nEnd - nStart, aNormPackage );
218                 aPureUri = aPureUri.replaceAt(
219                     nEnd + 1,
220                     aPureUri.getLength() - nEnd - 1,
221                     ::ucb_impl::urihelper::encodeURI( m_aPath ) );
222 
223                 m_aPackage
224                     = ::ucb_impl::urihelper::decodeSegment( aNormPackage );
225 				m_aPath = ::ucb_impl::urihelper::decodeSegment( m_aPath );
226 				m_aUri = m_aUri.replaceAt( 0,
227                                            ( nParam >= 0 )
228                                            ? nParam
229                                            : m_aUri.getLength(), aPureUri );
230 
231                 sal_Int32 nLastSlash = aPureUri.lastIndexOf( '/' );
232                 if ( nLastSlash != -1 )
233                 {
234                     m_aParentUri = aPureUri.copy( 0, nLastSlash );
235                     m_aName = ::ucb_impl::urihelper::decodeSegment(
236                         aPureUri.copy( nLastSlash + 1 ) );
237                 }
238             }
239 
240             // success
241             m_bValid = true;
242         }
243         else
244         {
245             // error, but remember that we did a init().
246             m_aPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
247         }
248     }
249 }
250