Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "surrogates.hxx"
30 : :
31 : : #include "osl/diagnose.h"
32 : : #include "rtl/strbuf.hxx"
33 : : #include "rtl/textenc.h"
34 : : #include "rtl/textcvt.h"
35 : : #include "rtl/uri.h"
36 : : #include "rtl/ustrbuf.h"
37 : : #include "rtl/ustrbuf.hxx"
38 : : #include "rtl/ustring.h"
39 : : #include "rtl/ustring.hxx"
40 : : #include "sal/types.h"
41 : : #include "sal/macros.h"
42 : :
43 : : #include <cstddef>
44 : :
45 : : namespace {
46 : :
47 : : std::size_t const nCharClassSize = 128;
48 : :
49 : : sal_Unicode const cEscapePrefix = 0x25; // '%'
50 : :
51 : 171793 : inline bool isDigit(sal_uInt32 nUtf32)
52 : : {
53 [ + + ][ + + ]: 171793 : return nUtf32 >= 0x30 && nUtf32 <= 0x39; // '0'--'9'
54 : : }
55 : :
56 : 1256418 : inline bool isAlpha(sal_uInt32 nUtf32)
57 : : {
58 : : // 'A'--'Z', 'a'--'z'
59 : : return (
60 : : (nUtf32 >= 0x41 && nUtf32 <= 0x5A) ||
61 : : (nUtf32 >= 0x61 && nUtf32 <= 0x7A)
62 [ + + ][ + - ]: 1256418 : );
[ + + ][ + - ]
63 : : }
64 : :
65 : 170277561 : inline bool isHighSurrogate(sal_uInt32 nUtf16)
66 : : {
67 [ + + ][ + ]: 170277561 : return SAL_RTL_IS_HIGH_SURROGATE(nUtf16);
68 : : }
69 : :
70 : 30 : inline bool isLowSurrogate(sal_uInt32 nUtf16)
71 : : {
72 [ - + ][ # # ]: 30 : return SAL_RTL_IS_LOW_SURROGATE(nUtf16);
73 : : }
74 : :
75 : 0 : inline sal_uInt32 combineSurrogates(sal_uInt32 high, sal_uInt32 low)
76 : : {
77 : 0 : return SAL_RTL_COMBINE_SURROGATES(high, low);
78 : : }
79 : :
80 : 353104 : inline int getHexWeight(sal_uInt32 nUtf32)
81 : : {
82 : : return nUtf32 >= 0x30 && nUtf32 <= 0x39 ? // '0'--'9'
83 : : static_cast< int >(nUtf32 - 0x30) :
84 : : nUtf32 >= 0x41 && nUtf32 <= 0x46 ? // 'A'--'F'
85 : : static_cast< int >(nUtf32 - 0x41 + 10) :
86 : : nUtf32 >= 0x61 && nUtf32 <= 0x66 ? // 'a'--'f'
87 : : static_cast< int >(nUtf32 - 0x61 + 10) :
88 [ + - ][ + + ]: 353104 : -1; // not a hex digit
[ + - ][ + + ]
[ + - ][ + - ]
89 : : }
90 : :
91 : 52577631 : inline bool isValid(sal_Bool const * pCharClass, sal_uInt32 nUtf32)
92 : : {
93 [ + - ][ + + ]: 52577631 : return nUtf32 < nCharClassSize && pCharClass[nUtf32];
94 : : }
95 : :
96 : 170566561 : inline void writeUnicode(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
97 : : sal_Unicode cChar)
98 : : {
99 : 170566561 : rtl_uStringbuffer_insert(pBuffer, pCapacity, (*pBuffer)->length, &cChar, 1);
100 : 170566553 : }
101 : :
102 : : enum EscapeType
103 : : {
104 : : EscapeNo,
105 : : EscapeChar,
106 : : EscapeOctet
107 : : };
108 : :
109 : : /* Read any of the following:
110 : :
111 : : - sequence of escape sequences representing character from eCharset,
112 : : translated to single UCS4 character; or
113 : :
114 : : - pair of UTF-16 surrogates, translated to single UCS4 character; or
115 : :
116 : : _ single UTF-16 character, extended to UCS4 character.
117 : : */
118 : 170453971 : sal_uInt32 readUcs4(sal_Unicode const ** pBegin, sal_Unicode const * pEnd,
119 : : bool bEncoded, rtl_TextEncoding eCharset,
120 : : EscapeType * pType)
121 : : {
122 : 170453971 : sal_uInt32 nChar = *(*pBegin)++;
123 : : int nWeight1;
124 : : int nWeight2;
125 [ + + ][ + + ]: 170453971 : if (nChar == cEscapePrefix && bEncoded && pEnd - *pBegin >= 2
[ + + ][ + - ]
[ + ][ + + ]
126 : 176462 : && (nWeight1 = getHexWeight((*pBegin)[0])) >= 0
127 : 176462 : && (nWeight2 = getHexWeight((*pBegin)[1])) >= 0)
128 : : {
129 : 176462 : *pBegin += 2;
130 : 176462 : nChar = static_cast< sal_uInt32 >(nWeight1 << 4 | nWeight2);
131 [ + + ]: 176462 : if (nChar <= 0x7F)
132 : 176387 : *pType = EscapeChar;
133 [ + - ]: 75 : else if (eCharset == RTL_TEXTENCODING_UTF8)
134 : : {
135 [ + + ][ + - ]: 75 : if (nChar >= 0xC0 && nChar <= 0xF4)
136 : : {
137 : : sal_uInt32 nEncoded;
138 : : int nShift;
139 : : sal_uInt32 nMin;
140 [ - + ]: 45 : if (nChar <= 0xDF)
141 : : {
142 : 0 : nEncoded = (nChar & 0x1F) << 6;
143 : 0 : nShift = 0;
144 : 0 : nMin = 0x80;
145 : : }
146 [ + - ]: 45 : else if (nChar <= 0xEF)
147 : : {
148 : 45 : nEncoded = (nChar & 0x0F) << 12;
149 : 45 : nShift = 6;
150 : 45 : nMin = 0x800;
151 : : }
152 : : else
153 : : {
154 : 0 : nEncoded = (nChar & 0x07) << 18;
155 : 0 : nShift = 12;
156 : 0 : nMin = 0x10000;
157 : : }
158 : 45 : sal_Unicode const * p = *pBegin;
159 : 45 : bool bUTF8 = true;
160 [ + + ]: 135 : for (; nShift >= 0; nShift -= 6)
161 : : {
162 [ + - ][ + - ]: 90 : if (pEnd - p < 3 || p[0] != cEscapePrefix
[ + - ][ + - ]
[ - + ][ - + ]
163 : 90 : || (nWeight1 = getHexWeight(p[1])) < 8
164 : : || nWeight1 > 11
165 : 90 : || (nWeight2 = getHexWeight(p[2])) < 0)
166 : : {
167 : 0 : bUTF8 = sal_False;
168 : 0 : break;
169 : : }
170 : 90 : p += 3;
171 : 90 : nEncoded |= ((nWeight1 & 3) << 4 | nWeight2) << nShift;
172 : : }
173 [ + - ][ + - ]: 75 : if (bUTF8 && nEncoded >= nMin && !isHighSurrogate(nEncoded)
[ + + + - ]
[ + - ][ + + ]
174 : 30 : && !isLowSurrogate(nEncoded) && nEncoded <= 0x10FFFF)
175 : : {
176 : 30 : *pBegin = p;
177 : 30 : *pType = EscapeChar;
178 : 30 : return nEncoded;
179 : : }
180 : : }
181 : 45 : *pType = EscapeOctet;
182 : : }
183 : : else
184 : : {
185 : 0 : rtl::OStringBuffer aBuf;
186 [ # # ]: 0 : aBuf.append(static_cast< char >(nChar));
187 : : rtl_TextToUnicodeConverter aConverter
188 [ # # ]: 0 : = rtl_createTextToUnicodeConverter(eCharset);
189 : 0 : sal_Unicode const * p = *pBegin;
190 : 0 : for (;;)
191 : : {
192 : : sal_Unicode aDst[2];
193 : : sal_uInt32 nInfo;
194 : : sal_Size nConverted;
195 : : sal_Size nDstSize = rtl_convertTextToUnicode(
196 : 0 : aConverter, 0, aBuf.getStr(), aBuf.getLength(), aDst,
197 : : SAL_N_ELEMENTS( aDst ),
198 : : (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
199 : : | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
200 : : | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR),
201 [ # # ]: 0 : &nInfo, &nConverted);
202 [ # # ]: 0 : if (nInfo == 0)
203 : : {
204 : : OSL_ASSERT(
205 : : nConverted
206 : : == sal::static_int_cast< sal_uInt32 >(
207 : : aBuf.getLength()));
208 [ # # ]: 0 : rtl_destroyTextToUnicodeConverter(aConverter);
209 : 0 : *pBegin = p;
210 : 0 : *pType = EscapeChar;
211 : : OSL_ASSERT(
212 : : nDstSize == 1
213 : : || (nDstSize == 2 && isHighSurrogate(aDst[0])
214 : : && isLowSurrogate(aDst[1])));
215 : : return nDstSize == 1
216 [ # # ]: 0 : ? aDst[0] : combineSurrogates(aDst[0], aDst[1]);
217 : : }
218 [ # # ][ # # ]: 0 : else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
[ # # ][ # # ]
[ # # ][ # # ]
219 : : && pEnd - p >= 3 && p[0] == cEscapePrefix
220 : 0 : && (nWeight1 = getHexWeight(p[1])) >= 0
221 : 0 : && (nWeight2 = getHexWeight(p[2])) >= 0)
222 : : {
223 : 0 : p += 3;
224 [ # # ]: 0 : aBuf.append(static_cast< char >(nWeight1 << 4 | nWeight2));
225 : : }
226 [ # # ][ # # ]: 0 : else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
[ # # ]
227 : : && p != pEnd && *p <= 0x7F)
228 : : {
229 [ # # ]: 0 : aBuf.append(static_cast< char >(*p++));
230 : : }
231 : : else
232 : : {
233 : : OSL_ASSERT(
234 : : (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
235 : : == 0);
236 : : break;
237 : : }
238 : : }
239 [ # # ]: 0 : rtl_destroyTextToUnicodeConverter(aConverter);
240 [ # # ]: 0 : *pType = EscapeOctet;
241 : : }
242 : 176432 : return nChar;
243 : : }
244 : : else
245 : : {
246 : 170277509 : *pType = EscapeNo;
247 : 170277509 : return isHighSurrogate(nChar) && *pBegin < pEnd
248 : 0 : && isLowSurrogate(**pBegin) ?
249 [ # # # # ]: 170453978 : combineSurrogates(nChar, *(*pBegin)++) : nChar;
[ - + ]
250 : : }
251 : : }
252 : :
253 : 117876208 : void writeUcs4(rtl_uString ** pBuffer, sal_Int32 * pCapacity, sal_uInt32 nUtf32)
254 : : {
255 : : OSL_ENSURE(nUtf32 <= 0x10FFFF, "bad UTF-32 char");
256 [ + - ]: 117876208 : if (nUtf32 <= 0xFFFF) {
257 : : writeUnicode(
258 : 117876208 : pBuffer, pCapacity, static_cast< sal_Unicode >(nUtf32));
259 : : } else {
260 : 0 : nUtf32 -= 0x10000;
261 : : writeUnicode(
262 : : pBuffer, pCapacity,
263 : 0 : static_cast< sal_Unicode >(nUtf32 >> 10 | 0xD800));
264 : : writeUnicode(
265 : : pBuffer, pCapacity,
266 : 0 : static_cast< sal_Unicode >((nUtf32 & 0x3FF) | 0xDC00));
267 : : }
268 : 117876213 : }
269 : :
270 : 56295 : void writeEscapeOctet(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
271 : : sal_uInt32 nOctet)
272 : : {
273 : : OSL_ENSURE(nOctet <= 0xFF, "bad octet");
274 : :
275 : : static sal_Unicode const aHex[16]
276 : : = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
277 : : 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; /* '0'--'9', 'A'--'F' */
278 : :
279 : 56295 : writeUnicode(pBuffer, pCapacity, cEscapePrefix);
280 : 56295 : writeUnicode(pBuffer, pCapacity, aHex[nOctet >> 4]);
281 : 56295 : writeUnicode(pBuffer, pCapacity, aHex[nOctet & 15]);
282 : 56295 : }
283 : :
284 : 56250 : bool writeEscapeChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
285 : : sal_uInt32 nUtf32, rtl_TextEncoding eCharset, bool bStrict)
286 : : {
287 : : OSL_ENSURE(nUtf32 <= 0x10FFFF, "bad UTF-32 char");
288 [ + - ]: 56250 : if (eCharset == RTL_TEXTENCODING_UTF8) {
289 [ + - ]: 56250 : if (nUtf32 < 0x80)
290 : 56250 : writeEscapeOctet(pBuffer, pCapacity, nUtf32);
291 [ # # ]: 0 : else if (nUtf32 < 0x800)
292 : : {
293 : 0 : writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 6 | 0xC0);
294 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
295 : : }
296 [ # # ]: 0 : else if (nUtf32 < 0x10000)
297 : : {
298 : 0 : writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 12 | 0xE0);
299 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
300 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
301 : : }
302 : : else
303 : : {
304 : 0 : writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 18 | 0xF0);
305 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 12 & 0x3F) | 0x80);
306 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80);
307 : 0 : writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80);
308 : : }
309 : : } else {
310 : : rtl_UnicodeToTextConverter aConverter
311 [ # # ]: 0 : = rtl_createUnicodeToTextConverter(eCharset);
312 : : sal_Unicode aSrc[2];
313 : : sal_Size nSrcSize;
314 [ # # ]: 0 : if (nUtf32 <= 0xFFFF)
315 : : {
316 : 0 : aSrc[0] = static_cast< sal_Unicode >(nUtf32);
317 : 0 : nSrcSize = 1;
318 : : }
319 : : else
320 : : {
321 : : aSrc[0] = static_cast< sal_Unicode >(
322 : 0 : ((nUtf32 - 0x10000) >> 10) | 0xD800);
323 : : aSrc[1] = static_cast< sal_Unicode >(
324 : 0 : ((nUtf32 - 0x10000) & 0x3FF) | 0xDC00);
325 : 0 : nSrcSize = 2;
326 : : }
327 : : sal_Char aDst[32]; // FIXME random value
328 : : sal_uInt32 nInfo;
329 : : sal_Size nConverted;
330 : : sal_Size nDstSize = rtl_convertUnicodeToText(
331 : : aConverter, 0, aSrc, nSrcSize, aDst, sizeof aDst,
332 : : RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
333 : : | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
334 : : | RTL_UNICODETOTEXT_FLAGS_FLUSH,
335 [ # # ]: 0 : &nInfo, &nConverted);
336 : : OSL_ASSERT((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0);
337 [ # # ]: 0 : rtl_destroyUnicodeToTextConverter(aConverter);
338 [ # # ]: 0 : if (nInfo == 0) {
339 : : OSL_ENSURE(nConverted == nSrcSize, "bad rtl_convertUnicodeToText");
340 [ # # ]: 0 : for (sal_Size i = 0; i < nDstSize; ++i)
341 : : writeEscapeOctet(pBuffer, pCapacity,
342 [ # # ]: 0 : static_cast< unsigned char >(aDst[i]));
343 : : // FIXME all octets are escaped, even if there is no need
344 : : } else {
345 [ # # ]: 0 : if (bStrict) {
346 : 0 : return false;
347 : : } else {
348 [ # # ]: 0 : writeUcs4(pBuffer, pCapacity, nUtf32);
349 : : }
350 : : }
351 : : }
352 : 56250 : return true;
353 : : }
354 : :
355 : : struct Component
356 : : {
357 : : sal_Unicode const * pBegin;
358 : : sal_Unicode const * pEnd;
359 : :
360 : 587955 : inline Component(): pBegin(0), pEnd(0) {}
361 : :
362 : 276931 : inline bool isPresent() const { return pBegin != 0; }
363 : :
364 : : inline sal_Int32 getLength() const;
365 : : };
366 : :
367 : 159340 : inline sal_Int32 Component::getLength() const
368 : : {
369 : : OSL_ENSURE(isPresent(), "taking length of non-present component");
370 : 159340 : return static_cast< sal_Int32 >(pEnd - pBegin);
371 : : }
372 : :
373 : 117591 : struct Components
374 : : {
375 : : Component aScheme;
376 : : Component aAuthority;
377 : : Component aPath;
378 : : Component aQuery;
379 : : Component aFragment;
380 : : };
381 : :
382 : 117591 : void parseUriRef(rtl_uString const * pUriRef, Components * pComponents)
383 : : {
384 : : // This algorithm is liberal and accepts various forms of illegal input.
385 : :
386 : 117591 : sal_Unicode const * pBegin = pUriRef->buffer;
387 : 117591 : sal_Unicode const * pEnd = pBegin + pUriRef->length;
388 : 117591 : sal_Unicode const * pPos = pBegin;
389 : :
390 [ + - ][ + + ]: 117591 : if (pPos != pEnd && isAlpha(*pPos))
[ + + ]
391 : : {
392 [ + + ]: 1333684 : for (sal_Unicode const * p = pPos + 1; p != pEnd; ++p)
393 : : {
394 [ + + ]: 1216583 : if (*p == ':')
395 : : {
396 : 77756 : pComponents->aScheme.pBegin = pBegin;
397 : 77756 : pComponents->aScheme.pEnd = ++p;
398 : 77756 : pPos = p;
399 : 77756 : break;
400 : : }
401 [ + + ][ + + ]: 1138827 : else if (!isAlpha(*p) && !isDigit(*p) && *p != '+' && *p != '-'
[ + - ][ + - ]
[ + + ][ + + ]
402 : : && *p != '.')
403 : : {
404 : 20202 : break;
405 : : }
406 : : }
407 : : }
408 : :
409 [ + - ][ + + ]: 117591 : if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/')
[ + - ]
410 : : {
411 : 39976 : pComponents->aAuthority.pBegin = pPos;
412 : 39976 : pPos += 2;
413 [ + - ][ - + ]: 39976 : while (pPos != pEnd && *pPos != '/' && *pPos != '?' && *pPos != '#')
[ # # ][ # # ]
[ - + ]
414 : 0 : ++pPos;
415 : 39976 : pComponents->aAuthority.pEnd = pPos;
416 : : }
417 : :
418 : 117591 : pComponents->aPath.pBegin = pPos;
419 [ + + ][ + - ]: 4635986 : while (pPos != pEnd && *pPos != '?' && * pPos != '#')
[ + - ][ + + ]
420 : 4518395 : ++pPos;
421 : 117591 : pComponents->aPath.pEnd = pPos;
422 : :
423 [ - + ][ # # ]: 117591 : if (pPos != pEnd && *pPos == '?')
424 : : {
425 : 0 : pComponents->aQuery.pBegin = pPos++;
426 [ # # ][ # # ]: 0 : while (pPos != pEnd && * pPos != '#')
[ # # ]
427 : 0 : ++pPos;
428 : 0 : pComponents->aQuery.pEnd = pPos;
429 : : }
430 : :
431 [ - + ]: 117591 : if (pPos != pEnd)
432 : : {
433 : : OSL_ASSERT(*pPos == '#');
434 : 0 : pComponents->aFragment.pBegin = pPos;
435 : 0 : pComponents->aFragment.pEnd = pEnd;
436 : : }
437 : 117591 : }
438 : :
439 : 39835 : rtl::OUString joinPaths(Component const & rBasePath, Component const & rRelPath)
440 : : {
441 : : OSL_ASSERT(rBasePath.isPresent() && *rBasePath.pBegin == '/');
442 : : OSL_ASSERT(rRelPath.isPresent());
443 : :
444 : : // The invariant of aBuffer is that it always starts and ends with a slash
445 : : // (until probably right at the end of the algorithm, when the last segment
446 : : // of rRelPath is added, which does not necessarily end in a slash):
447 : 39835 : rtl::OUStringBuffer aBuffer(rBasePath.getLength() + rRelPath.getLength());
448 : : // XXX numeric overflow
449 : :
450 : : // Segments "." and ".." within rBasePath are not conisdered special (but
451 : : // are also not removed by ".." segments within rRelPath), RFC 2396 seems a
452 : : // bit unclear about this point:
453 : 39835 : sal_Int32 nFixed = 1;
454 : 39835 : sal_Unicode const * p = rBasePath.pBegin + 1;
455 [ + + ]: 2927842 : for (sal_Unicode const * q = p; q != rBasePath.pEnd; ++q)
456 [ + + ]: 2888007 : if (*q == '/')
457 : : {
458 [ - + ][ # # ]: 319659 : if (
[ + + ][ + - ]
[ + - ]
459 : : (q - p == 1 && p[0] == '.') ||
460 : 490 : (q - p == 2 && p[0] == '.' && p[1] == '.')
461 : : )
462 : : {
463 : 490 : nFixed = q + 1 - rBasePath.pBegin;
464 : : }
465 : 319659 : p = q + 1;
466 : : }
467 [ + - ]: 39835 : aBuffer.append(rBasePath.pBegin, p - rBasePath.pBegin);
468 : :
469 : 39835 : p = rRelPath.pBegin;
470 [ + - ]: 39835 : if (p != rRelPath.pEnd)
471 : 40325 : for (;;)
472 : : {
473 : 40325 : sal_Unicode const * q = p;
474 : : sal_Unicode const * r;
475 : 511968 : for (;;)
476 : : {
477 [ + + ]: 552293 : if (q == rRelPath.pEnd)
478 : : {
479 : 39835 : r = q;
480 : 39835 : break;
481 : : }
482 [ + + ]: 512458 : if (*q == '/')
483 : : {
484 : 490 : r = q + 1;
485 : 490 : break;
486 : : }
487 : 511968 : ++q;
488 : : }
489 [ - + ][ # # ]: 40325 : if (q - p == 2 && p[0] == '.' && p[1] == '.')
[ # # ]
490 : : {
491 : : // Erroneous excess segments ".." within rRelPath are left
492 : : // intact, as the examples in RFC 2396, section C.2, suggest:
493 : 0 : sal_Int32 i = aBuffer.getLength() - 1;
494 [ # # ]: 0 : if (i < nFixed)
495 : : {
496 [ # # ]: 0 : aBuffer.append(p, r - p);
497 : 0 : nFixed += 3;
498 : : }
499 : : else
500 : : {
501 [ # # ][ # # ]: 0 : while (i > 0 && aBuffer[i - 1] != '/')
[ # # ]
502 : 0 : --i;
503 [ # # ]: 0 : aBuffer.setLength(i);
504 : 0 : }
505 : : }
506 [ + + ][ - + ]: 40325 : else if (q - p != 1 || *p != '.')
507 [ + - ]: 39835 : aBuffer.append(p, r - p);
508 [ + + ]: 40325 : if (q == rRelPath.pEnd)
509 : 39835 : break;
510 : 490 : p = q + 1;
511 : : }
512 : :
513 [ + - ]: 39835 : return aBuffer.makeStringAndClear();
514 : : }
515 : :
516 : : }
517 : :
518 : 36622 : sal_Bool const * SAL_CALL rtl_getUriCharClass(rtl_UriCharClass eCharClass)
519 : : SAL_THROW_EXTERN_C()
520 : : {
521 : : static sal_Bool const aCharClass[][nCharClassSize]
522 : : = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* None */
523 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
524 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* !"#$%&'()*+,-./*/
525 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*0123456789:;<=>?*/
526 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*@ABCDEFGHIJKLMNO*/
527 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*PQRSTUVWXYZ[\]^_*/
528 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*`abcdefghijklmno*/
529 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /*pqrstuvwxyz{|}~ */
530 : : },
531 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Uric */
532 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
533 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./*/
534 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*0123456789:;<=>?*/
535 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
536 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*PQRSTUVWXYZ[\]^_*/
537 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
538 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
539 : : },
540 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* UricNoSlash */
541 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
542 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
543 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*0123456789:;<=>?*/
544 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
545 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
546 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
547 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
548 : : },
549 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* RelSegment */
550 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
551 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
552 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/
553 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
554 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
555 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
556 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
557 : : },
558 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* RegName */
559 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
560 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
561 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/
562 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
563 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
564 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
565 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
566 : : },
567 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Userinfo */
568 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
569 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
570 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/
571 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
572 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
573 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
574 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
575 : : },
576 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar */
577 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
578 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
579 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /*0123456789:;<=>?*/
580 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
581 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
582 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
583 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
584 : : },
585 : : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* UnoParamValue */
586 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
587 : : 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* !"#$%&'()*+,-./*/
588 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*0123456789:;<=>?*/
589 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
590 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/
591 : : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
592 : : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
593 : : }};
594 : : OSL_ENSURE(
595 : : (eCharClass >= 0
596 : : && (sal::static_int_cast< std::size_t >(eCharClass)
597 : : < SAL_N_ELEMENTS(aCharClass))),
598 : : "bad eCharClass");
599 : 36622 : return aCharClass[eCharClass];
600 : : }
601 : :
602 : 693045 : void SAL_CALL rtl_uriEncode(rtl_uString * pText, sal_Bool const * pCharClass,
603 : : rtl_UriEncodeMechanism eMechanism,
604 : : rtl_TextEncoding eCharset, rtl_uString ** pResult)
605 : : SAL_THROW_EXTERN_C()
606 : : {
607 : : OSL_ENSURE(!pCharClass[0x25], "bad pCharClass");
608 : : // make sure the percent sign is encoded...
609 : :
610 : 693045 : sal_Unicode const * p = pText->buffer;
611 : 693045 : sal_Unicode const * pEnd = p + pText->length;
612 : 693045 : sal_Int32 nCapacity = pText->length;
613 : 693045 : rtl_uString_new_WithLength(pResult, nCapacity);
614 [ + + ]: 53270765 : while (p < pEnd)
615 : : {
616 : : EscapeType eType;
617 : : sal_uInt32 nUtf32 = readUcs4(
618 : : &p, pEnd,
619 : : (eMechanism == rtl_UriEncodeKeepEscapes
620 : : || eMechanism == rtl_UriEncodeCheckEscapes
621 : : || eMechanism == rtl_UriEncodeStrictKeepEscapes),
622 [ + + ][ + ]: 52577720 : eCharset, &eType);
[ - + ][ + - ]
623 [ + + - - ]: 52577716 : switch (eType)
624 : : {
625 : : case EscapeNo:
626 [ + + ]: 52577632 : if (isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
627 : : writeUnicode(pResult, &nCapacity,
628 [ + - ]: 52521457 : static_cast< sal_Unicode >(nUtf32));
629 [ - + ]: 56166 : else if (!writeEscapeChar(
630 : : pResult, &nCapacity, nUtf32, eCharset,
631 : : (eMechanism == rtl_UriEncodeStrict
632 [ + - ][ - + ]: 56166 : || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
[ + - ]
633 : : {
634 : 0 : rtl_uString_new(pResult);
635 : : return;
636 : : }
637 : 52577636 : break;
638 : :
639 : : case EscapeChar:
640 [ - + # # ]: 84 : if (eMechanism == rtl_UriEncodeCheckEscapes
[ - + ]
641 : 0 : && isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F
642 : : writeUnicode(pResult, &nCapacity,
643 [ # # ]: 0 : static_cast< sal_Unicode >(nUtf32));
644 [ - + ]: 84 : else if (!writeEscapeChar(
645 : : pResult, &nCapacity, nUtf32, eCharset,
646 : : (eMechanism == rtl_UriEncodeStrict
647 [ + - ][ - + ]: 84 : || eMechanism == rtl_UriEncodeStrictKeepEscapes)))
[ + - ]
648 : : {
649 : 0 : rtl_uString_new(pResult);
650 : : return;
651 : : }
652 : 84 : break;
653 : :
654 : : case EscapeOctet:
655 [ # # ]: 0 : writeEscapeOctet(pResult, &nCapacity, nUtf32);
656 : 52577720 : break;
657 : : }
658 : : }
659 [ + - ]: 693045 : *pResult = rtl_uStringBuffer_makeStringAndClear( pResult, &nCapacity );
660 : : }
661 : :
662 : 1253064 : void SAL_CALL rtl_uriDecode(rtl_uString * pText,
663 : : rtl_UriDecodeMechanism eMechanism,
664 : : rtl_TextEncoding eCharset, rtl_uString ** pResult)
665 : : SAL_THROW_EXTERN_C()
666 : : {
667 [ - + + ]: 1253064 : switch (eMechanism)
668 : : {
669 : : case rtl_UriDecodeNone:
670 : 0 : rtl_uString_assign(pResult, pText);
671 : 0 : break;
672 : :
673 : : case rtl_UriDecodeToIuri:
674 : 10 : eCharset = RTL_TEXTENCODING_UTF8;
675 : : default: // rtl_UriDecodeWithCharset, rtl_UriDecodeStrict
676 : : {
677 : 1253064 : sal_Unicode const * p = pText->buffer;
678 : 1253064 : sal_Unicode const * pEnd = p + pText->length;
679 : 1253064 : sal_Int32 nCapacity = pText->length;
680 : 1253064 : rtl_uString_new_WithLength(pResult, nCapacity);
681 [ + + ]: 119129323 : while (p < pEnd)
682 : : {
683 : : EscapeType eType;
684 [ + - ]: 117876259 : sal_uInt32 nUtf32 = readUcs4(&p, pEnd, true, eCharset, &eType);
685 [ + + + - ]: 117876260 : switch (eType)
686 : : {
687 : : case EscapeChar:
688 [ + + ][ - + ]: 176333 : if (nUtf32 <= 0x7F && eMechanism == rtl_UriDecodeToIuri)
689 : : {
690 [ # # ]: 0 : writeEscapeOctet(pResult, &nCapacity, nUtf32);
691 : 0 : break;
692 : : }
693 : : case EscapeNo:
694 [ + - ]: 117876215 : writeUcs4(pResult, &nCapacity, nUtf32);
695 : 117876214 : break;
696 : :
697 : : case EscapeOctet:
698 [ - + ]: 45 : if (eMechanism == rtl_UriDecodeStrict) {
699 : 0 : rtl_uString_new(pResult);
700 : 1253064 : return;
701 : : }
702 [ + - ]: 45 : writeEscapeOctet(pResult, &nCapacity, nUtf32);
703 : 117876259 : break;
704 : : }
705 : : }
706 [ + - ]: 1253064 : *pResult = rtl_uStringBuffer_makeStringAndClear( pResult, &nCapacity );
707 : : }
708 : 1253064 : break;
709 : : }
710 : : }
711 : :
712 : 77756 : sal_Bool SAL_CALL rtl_uriConvertRelToAbs(rtl_uString * pBaseUriRef,
713 : : rtl_uString * pRelUriRef,
714 : : rtl_uString ** pResult,
715 : : rtl_uString ** pException)
716 : : SAL_THROW_EXTERN_C()
717 : : {
718 : : // If pRelUriRef starts with a scheme component it is an absolute URI
719 : : // reference, and we are done (i.e., this algorithm does not support
720 : : // backwards-compatible relative URIs starting with a scheme component, see
721 : : // RFC 2396, section 5.2, step 3):
722 : 77756 : Components aRelComponents;
723 : 77756 : parseUriRef(pRelUriRef, &aRelComponents);
724 [ + + ]: 77756 : if (aRelComponents.aScheme.isPresent())
725 : : {
726 : 37921 : rtl_uString_assign(pResult, pRelUriRef);
727 : 37921 : return true;
728 : : }
729 : :
730 : : // Parse pBaseUriRef; if the scheme component is not present or not valid,
731 : : // or the path component is not empty and starts with anything but a slash,
732 : : // an exception is raised:
733 : 39835 : Components aBaseComponents;
734 : 39835 : parseUriRef(pBaseUriRef, &aBaseComponents);
735 [ - + ]: 39835 : if (!aBaseComponents.aScheme.isPresent())
736 : : {
737 : 0 : rtl::OUString aMessage(pBaseUriRef);
738 : : aMessage += rtl::OUString(
739 : : RTL_CONSTASCII_USTRINGPARAM(
740 [ # # ]: 0 : " does not start with a scheme component"));
741 : : rtl_uString_assign(pException,
742 : 0 : const_cast< rtl::OUString & >(aMessage).pData);
743 : 0 : return false;
744 : : }
745 [ + - ][ - + ]: 39835 : if (aBaseComponents.aPath.pBegin != aBaseComponents.aPath.pEnd
746 : : && *aBaseComponents.aPath.pBegin != '/')
747 : : {
748 : 0 : rtl::OUString aMessage(pBaseUriRef);
749 : : aMessage += rtl::OUString(
750 : : RTL_CONSTASCII_USTRINGPARAM(
751 [ # # ]: 0 : "path component does not start with slash"));
752 : 0 : rtl_uString_assign(pException, aMessage.pData);
753 : 0 : return false;
754 : : }
755 : :
756 : : // Use the algorithm from RFC 2396, section 5.2, to turn the relative URI
757 : : // into an absolute one (if the relative URI is a reference to the "current
758 : : // document," the "current document" is here taken to be the base URI):
759 : 39835 : rtl::OUStringBuffer aBuffer;
760 : : aBuffer.append(aBaseComponents.aScheme.pBegin,
761 [ + - ]: 39835 : aBaseComponents.aScheme.getLength());
762 [ - + ]: 39835 : if (aRelComponents.aAuthority.isPresent())
763 : : {
764 : : aBuffer.append(aRelComponents.aAuthority.pBegin,
765 [ # # ]: 0 : aRelComponents.aAuthority.getLength());
766 : : aBuffer.append(aRelComponents.aPath.pBegin,
767 [ # # ]: 0 : aRelComponents.aPath.getLength());
768 [ # # ]: 0 : if (aRelComponents.aQuery.isPresent())
769 : : aBuffer.append(aRelComponents.aQuery.pBegin,
770 [ # # ]: 0 : aRelComponents.aQuery.getLength());
771 : : }
772 : : else
773 : : {
774 [ + - ]: 39835 : if (aBaseComponents.aAuthority.isPresent())
775 : : aBuffer.append(aBaseComponents.aAuthority.pBegin,
776 [ + - ]: 39835 : aBaseComponents.aAuthority.getLength());
777 [ - + # # ]: 39835 : if (aRelComponents.aPath.pBegin == aRelComponents.aPath.pEnd
[ - + ]
778 : 0 : && !aRelComponents.aQuery.isPresent())
779 : : {
780 : : aBuffer.append(aBaseComponents.aPath.pBegin,
781 [ # # ]: 0 : aBaseComponents.aPath.getLength());
782 [ # # ]: 0 : if (aBaseComponents.aQuery.isPresent())
783 : : aBuffer.append(aBaseComponents.aQuery.pBegin,
784 [ # # ]: 0 : aBaseComponents.aQuery.getLength());
785 : : }
786 : : else
787 : : {
788 [ - + ]: 39835 : if (*aRelComponents.aPath.pBegin == '/')
789 : : aBuffer.append(aRelComponents.aPath.pBegin,
790 [ # # ]: 0 : aRelComponents.aPath.getLength());
791 : : else
792 : : aBuffer.append(joinPaths(aBaseComponents.aPath,
793 [ + - ][ + - ]: 39835 : aRelComponents.aPath));
794 [ - + ]: 39835 : if (aRelComponents.aQuery.isPresent())
795 : : aBuffer.append(aRelComponents.aQuery.pBegin,
796 [ # # ]: 0 : aRelComponents.aQuery.getLength());
797 : : }
798 : : }
799 [ - + ]: 39835 : if (aRelComponents.aFragment.isPresent())
800 : : aBuffer.append(aRelComponents.aFragment.pBegin,
801 [ # # ]: 0 : aRelComponents.aFragment.getLength());
802 [ + - ]: 39835 : rtl_uString_assign(pResult, aBuffer.makeStringAndClear().pData);
803 : 77756 : return true;
804 : : }
805 : :
806 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|