1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "file_url.hxx"
26 #include <string_view>
30 #include <o3tl/safeint.hxx>
31 #include <osl/file.hxx>
32 #include <osl/security.hxx>
33 #include <osl/socket.h>
34 #include <oslsocket.hxx>
35 #include <osl/diagnose.h>
36 #include <osl/thread.h>
37 #include <osl/process.h>
39 #include <rtl/character.hxx>
40 #include <rtl/strbuf.hxx>
42 #include <rtl/uri.hxx>
43 #include <rtl/ustring.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <rtl/textcvt.h>
46 #include <sal/log.hxx>
48 #include <uri_internal.hxx>
50 #include "file_error_transl.hxx"
51 #include "file_path_helper.hxx"
53 #include "uunxapi.hxx"
59 This file contains the part that handles File URLs.
61 File URLs as scheme specific notion of URIs
62 (RFC2396) may be handled platform independent, but
63 will not in osl which is considered wrong.
64 Future version of osl should handle File URLs this
65 way. In rtl/uri there is already a URI parser etc.
66 so this code should be consolidated.
74 // A slightly modified version of Pchar in rtl/source/uri.c, but without
76 constexpr auto uriCharClass
= rtl::createUriCharClass(
77 u8
"!$&'()*+,-./0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~");
81 oslFileError SAL_CALL
osl_getCanonicalName( rtl_uString
* ustrFileURL
, rtl_uString
** pustrValidURL
)
83 OSL_FAIL("osl_getCanonicalName not implemented");
85 rtl_uString_newFromString(pustrValidURL
, ustrFileURL
);
86 return osl_File_E_None
;
91 class UnicodeToTextConverter_Impl
93 rtl_UnicodeToTextConverter m_converter
;
95 UnicodeToTextConverter_Impl()
96 : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
99 ~UnicodeToTextConverter_Impl()
101 rtl_destroyUnicodeToTextConverter (m_converter
);
104 static UnicodeToTextConverter_Impl
& getInstance()
106 static UnicodeToTextConverter_Impl g_theConverter
;
107 return g_theConverter
;
111 sal_Unicode
const * pSrcBuf
, sal_Size nSrcChars
, char * pDstBuf
, sal_Size nDstBytes
,
112 sal_uInt32 nFlags
, sal_uInt32
* pInfo
, sal_Size
* pSrcCvtChars
)
114 OSL_ASSERT(m_converter
!= nullptr);
115 return rtl_convertUnicodeToText (
116 m_converter
, nullptr, pSrcBuf
, nSrcChars
, pDstBuf
, nDstBytes
, nFlags
, pInfo
, pSrcCvtChars
);
120 bool convert(OUStringBuffer
const & in
, OStringBuffer
* append
) {
121 assert(append
!= nullptr);
122 for (sal_Size nConvert
= in
.getLength();;) {
123 auto const oldLen
= append
->getLength();
125 std::max(nConvert
, sal_Size(PATH_MAX
)),
126 sal_Size(std::numeric_limits
<sal_Int32
>::max() - oldLen
));
127 // approximation of required converted size
128 auto s
= append
->appendUninitialized(n
);
131 //TODO: context, for reliable treatment of DESTBUFFERTOSMALL:
132 n
= UnicodeToTextConverter_Impl::getInstance().convert(
133 in
.getStr() + in
.getLength() - nConvert
, nConvert
, s
, n
,
134 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
| RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
135 | RTL_UNICODETOTEXT_FLAGS_FLUSH
),
137 if ((info
& RTL_UNICODETOTEXT_INFO_ERROR
) != 0) {
140 append
->setLength(oldLen
+ n
);
141 assert(converted
<= nConvert
);
142 nConvert
-= converted
;
143 assert((nConvert
== 0) == ((info
& RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL
) == 0));
144 if ((info
& RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL
) == 0) {
151 bool decodeFromUtf8(std::u16string_view text
, OString
* result
) {
152 assert(result
!= nullptr);
153 auto p
= text
.data();
154 auto const end
= p
+ text
.size();
155 OUStringBuffer
ubuf(static_cast<int>(text
.size()));
156 OStringBuffer
bbuf(PATH_MAX
);
158 rtl::uri::detail::EscapeType t
;
159 sal_uInt32 c
= rtl::uri::detail::readUcs4(&p
, end
, true, RTL_TEXTENCODING_UTF8
, &t
);
161 case rtl::uri::detail::EscapeNo
:
166 case rtl::uri::detail::EscapeChar
:
167 if (rtl::isSurrogate(c
)) {
172 case rtl::uri::detail::EscapeOctet
:
173 if (!convert(ubuf
, &bbuf
)) {
178 bbuf
.append(char(c
));
182 if (!convert(ubuf
, &bbuf
)) {
185 *result
= bbuf
.makeStringAndClear();
189 template<typename T
> oslFileError
getSystemPathFromFileUrl(
190 OUString
const & url
, T
* path
, bool resolveHome
)
192 assert(path
!= nullptr);
193 // For compatibility with assumptions in other parts of the code base,
194 // assume that anything starting with a slash is a system path instead of a
195 // (relative) file URL (except if it starts with two slashes, in which case
196 // it is a relative URL with an authority component):
198 || (url
[0] == '/' && (url
.getLength() == 1 || url
[1] != '/')))
200 return osl_File_E_INVAL
;
202 // Check for non file scheme:
204 if (rtl::isAsciiAlpha(url
[0])) {
205 for (sal_Int32 j
= 1; j
!= url
.getLength(); ++j
) {
208 if (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
209 url
.pData
->buffer
, j
,
210 RTL_CONSTASCII_STRINGPARAM("file"))
213 return osl_File_E_INVAL
;
218 if (!rtl::isAsciiAlphanumeric(c
) && c
!= '+' && c
!= '-'
225 // Handle query or fragment:
226 if (url
.indexOf('?', i
) != -1 || url
.indexOf('#', i
) != -1)
227 return osl_File_E_INVAL
;
228 // Handle authority, supporting a host of "localhost", "127.0.0.1", or the exact value (e.g.,
229 // not supporting an additional final dot, for simplicity) reported by osl_getLocalHostnameFQDN
230 // (and, in each case, ignoring case of ASCII letters):
231 if (url
.getLength() - i
>= 2 && url
[i
] == '/' && url
[i
+ 1] == '/')
234 sal_Int32 j
= url
.indexOf('/', i
);
238 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
239 url
.pData
->buffer
+ i
, j
- i
,
240 RTL_CONSTASCII_STRINGPARAM("localhost"))
242 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
243 url
.pData
->buffer
+ i
, j
- i
,
244 RTL_CONSTASCII_STRINGPARAM("127.0.0.1"))
248 // The 'file' URI Scheme does imply that we want a FQDN in this case
249 // See https://tools.ietf.org/html/rfc8089#section-3
250 if (osl_getLocalHostnameFQDN(&hostname
.pData
) != osl_Socket_Ok
251 || (rtl_ustr_compareIgnoreAsciiCase_WithLength(
252 url
.pData
->buffer
+ i
, j
- i
, hostname
.getStr(), hostname
.getLength())
255 return osl_File_E_INVAL
;
260 // Handle empty path:
261 if (i
== url
.getLength())
264 return osl_File_E_None
;
266 // Path must not contain %2F:
267 if (url
.indexOf("%2F", i
) != -1 || url
.indexOf("%2f", i
) != -1)
268 return osl_File_E_INVAL
;
270 if constexpr (std::is_same_v
<T
, rtl::OString
>) {
271 if (!decodeFromUtf8(url
.subView(i
), path
)) {
272 return osl_File_E_INVAL
;
274 } else if constexpr (std::is_same_v
<T
, rtl::OUString
>) {
275 *path
= rtl::Uri::decode(
276 url
.copy(i
), rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
);
278 static_assert(std::is_same_v
<T
, rtl::OString
> || std::is_same_v
<T
, rtl::OUString
>);
280 // Path must not contain %2F:
281 if (path
->indexOf('\0') != -1)
282 return osl_File_E_INVAL
;
284 // Handle ~ notation:
285 if (resolveHome
&& path
->getLength() >= 2 && (*path
)[1] == '~')
287 sal_Int32 j
= path
->indexOf('/', 2);
289 j
= path
->getLength();
294 if (!osl::Security().getHomeDir(home
))
296 SAL_WARN("sal.file", "osl::Security::getHomeDir failed");
297 return osl_File_E_INVAL
;
300 i
= url
.indexOf('/', i
+ 1);
307 //TODO: cheesy way of ensuring home's path ends in slash:
308 if (!home
.isEmpty() && home
[home
.getLength() - 1] != '/')
312 home
= rtl::Uri::convertRelToAbs(home
, url
.copy(i
));
314 catch (rtl::MalformedUriException
& e
)
316 SAL_WARN("sal.file", "rtl::MalformedUriException " << e
.getMessage());
317 return osl_File_E_INVAL
;
319 return getSystemPathFromFileUrl(home
, path
, false);
321 // FIXME: replace ~user with user's home directory
322 return osl_File_E_INVAL
;
324 return osl_File_E_None
;
329 oslFileError SAL_CALL
osl_getSystemPathFromFileURL( rtl_uString
*ustrFileURL
, rtl_uString
**pustrSystemPath
)
335 e
= getSystemPathFromFileUrl(
336 OUString::unacquired(&ustrFileURL
), &path
, true);
338 catch (std::length_error
&)
340 e
= osl_File_E_RANGE
;
343 if (e
== osl_File_E_None
)
344 rtl_uString_assign(pustrSystemPath
, path
.pData
);
349 oslFileError SAL_CALL
osl_getFileURLFromSystemPath( rtl_uString
*ustrSystemPath
, rtl_uString
**pustrFileURL
)
351 rtl_uString
*pTmp
= nullptr;
354 auto const & systemPath
= OUString::unacquired(&ustrSystemPath
);
356 if( systemPath
.isEmpty() )
357 return osl_File_E_INVAL
;
359 if( systemPath
.startsWith( "file:" ) )
360 return osl_File_E_INVAL
;
362 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
363 if( systemPath
.startsWith("~") )
365 /* check if another user is specified */
366 if( ( systemPath
.getLength() == 1 ) ||
367 ( systemPath
[1] == '/' ) )
369 /* osl_getHomeDir returns file URL */
370 oslSecurity pSecurity
= osl_getCurrentSecurity();
371 osl_getHomeDir( pSecurity
, &pTmp
);
372 osl_freeSecurityHandle( pSecurity
);
375 return osl_File_E_INVAL
;
377 /* remove "file://" prefix */
378 rtl_uString_newFromStr_WithLength( &pTmp
, pTmp
->buffer
+ 7, pTmp
->length
- 7 );
380 /* replace '~' in original string */
381 rtl_uString_newReplaceStrAt( &pTmp
, systemPath
.pData
, 0, 1, pTmp
);
385 /* FIXME: replace ~user with users home directory */
386 return osl_File_E_INVAL
;
390 /* check if initial string contains repeated '/' characters */
391 nIndex
= systemPath
.indexOf( "//" );
395 sal_Int32 nDeleted
= 0;
397 /* if pTmp is not already allocated, copy systemPath for modification */
398 if( pTmp
== nullptr )
399 rtl_uString_newFromString( &pTmp
, systemPath
.pData
);
401 /* adapt index to pTmp */
402 nIndex
+= pTmp
->length
- systemPath
.getLength();
404 /* replace repeated '/' characters with a single '/' */
405 for( nSrcIndex
= nIndex
+ 1; nSrcIndex
< pTmp
->length
; nSrcIndex
++ )
407 if( (pTmp
->buffer
[nSrcIndex
] == '/') && (pTmp
->buffer
[nIndex
] == '/') )
410 pTmp
->buffer
[++nIndex
] = pTmp
->buffer
[nSrcIndex
];
413 /* adjust length member */
414 pTmp
->length
-= nDeleted
;
417 if( pTmp
== nullptr )
418 rtl_uString_assign( &pTmp
, systemPath
.pData
);
420 /* file URLs must be URI encoded */
421 rtl_uriEncode( pTmp
, uriCharClass
.data(), rtl_UriEncodeIgnoreEscapes
, RTL_TEXTENCODING_UTF8
, pustrFileURL
);
423 rtl_uString_release( pTmp
);
425 /* absolute urls should start with 'file://' */
426 if( (*pustrFileURL
)->buffer
[0] == '/' )
428 rtl_uString
*pProtocol
= nullptr;
430 rtl_uString_newFromAscii( &pProtocol
, "file://" );
431 rtl_uString_newConcat( pustrFileURL
, pProtocol
, *pustrFileURL
);
432 rtl_uString_release( pProtocol
);
435 return osl_File_E_None
;
439 * relative URLs are not accepted
441 oslFileError
getSystemPathFromFileURL_Ex(
442 rtl_uString
*ustrFileURL
, rtl_uString
**pustrSystemPath
)
444 rtl_uString
* temp
= nullptr;
445 oslFileError osl_error
= osl_getSystemPathFromFileURL(ustrFileURL
, &temp
);
447 if (osl_error
== osl_File_E_None
)
449 if (temp
->buffer
[0] == '/')
451 *pustrSystemPath
= temp
;
455 rtl_uString_release(temp
);
456 osl_error
= osl_File_E_INVAL
;
466 /** Helper function, return a pointer to the final '\0'
470 sal_Unicode
* ustrtoend(sal_Unicode
* pStr
)
472 return (pStr
+ rtl_ustr_getLength(pStr
));
475 sal_Unicode
* ustrchrcat(const sal_Unicode chr
, sal_Unicode
* d
)
477 sal_Unicode
* p
= ustrtoend(d
);
483 bool _islastchr(sal_Unicode
* pStr
, sal_Unicode Chr
)
485 sal_Unicode
* p
= ustrtoend(pStr
);
492 Remove the last part of a path, a path that has
493 only a '/' or no '/' at all will be returned
497 sal_Unicode
* _rmlastpathtoken(sal_Unicode
* aPath
)
499 /* we may always skip -2 because we
500 may at least stand on a '/' but
501 either there is no other character
502 before this '/' or it's another
503 character than the '/'
505 sal_Unicode
* p
= ustrtoend(aPath
) - 2;
507 /* move back to the next path separator
508 or to the start of the string */
509 while ((p
> aPath
) && (*p
!= '/'))
528 oslFileError
_osl_resolvepath(
529 /*inout*/ sal_Unicode
* path
,
530 /*inout*/ bool* failed
)
532 oslFileError ferr
= osl_File_E_None
;
536 char unresolved_path
[PATH_MAX
];
537 if (!UnicodeToText(unresolved_path
, sizeof(unresolved_path
), path
, rtl_ustr_getLength(path
)))
538 return oslTranslateFileError(ENAMETOOLONG
);
540 char resolved_path
[PATH_MAX
];
541 if (realpath(unresolved_path
, resolved_path
))
543 if (!TextToUnicode(resolved_path
, strlen(resolved_path
), path
, PATH_MAX
))
544 return oslTranslateFileError(ENAMETOOLONG
);
548 if (EACCES
== errno
|| ENOTDIR
== errno
|| ENOENT
== errno
)
551 ferr
= oslTranslateFileError(errno
);
559 Works even with non existing paths. The resulting path must not exceed
560 PATH_MAX else osl_File_E_NAMETOOLONG is the result
563 oslFileError
osl_getAbsoluteFileURL_impl_(const OUString
& unresolved_path
, OUString
& resolved_path
)
565 /* the given unresolved path must not exceed PATH_MAX */
566 if (unresolved_path
.getLength() >= (PATH_MAX
- 2))
567 return oslTranslateFileError(ENAMETOOLONG
);
569 sal_Unicode path_resolved_so_far
[PATH_MAX
];
570 const sal_Unicode
* punresolved
= unresolved_path
.getStr();
571 sal_Unicode
* presolvedsf
= path_resolved_so_far
;
573 /* reserve space for leading '/' and trailing '\0'
574 do not exceed this limit */
575 sal_Unicode
* sentinel
= path_resolved_so_far
+ PATH_MAX
- 2;
577 /* if realpath fails with error ENOTDIR, EACCES or ENOENT
578 we will not call it again, because _osl_realpath should also
579 work with non existing directories etc. */
580 bool realpath_failed
= false;
583 path_resolved_so_far
[0] = '\0';
585 while (*punresolved
!= '\0')
587 /* ignore '/.' , skip one part back when '/..' */
588 if ((*punresolved
== '.') && (*presolvedsf
== '/'))
590 if (*(punresolved
+ 1) == '\0')
595 if (*(punresolved
+ 1) == '/')
600 if ((*(punresolved
+ 1) == '.') && (*(punresolved
+ 2) == '\0' || (*(punresolved
+ 2) == '/')))
602 _rmlastpathtoken(path_resolved_so_far
);
604 presolvedsf
= ustrtoend(path_resolved_so_far
) - 1;
606 if (*(punresolved
+ 2) == '/')
614 /* a file or directory name may start with '.' */
615 if ((presolvedsf
= ustrtoend(path_resolved_so_far
)) > sentinel
)
616 return oslTranslateFileError(ENAMETOOLONG
);
618 ustrchrcat(*punresolved
++, path_resolved_so_far
);
620 if (*punresolved
== '\0' && !realpath_failed
)
622 ferr
= _osl_resolvepath(
623 path_resolved_so_far
,
626 if (ferr
!= osl_File_E_None
)
630 else if (*punresolved
== '/')
632 if ((presolvedsf
= ustrtoend(path_resolved_so_far
)) > sentinel
)
633 return oslTranslateFileError(ENAMETOOLONG
);
635 ustrchrcat(*punresolved
++, path_resolved_so_far
);
637 if (!realpath_failed
)
639 ferr
= _osl_resolvepath(
640 path_resolved_so_far
,
643 if (ferr
!= osl_File_E_None
)
646 if (!_islastchr(path_resolved_so_far
, '/'))
648 if ((presolvedsf
= ustrtoend(path_resolved_so_far
)) > sentinel
)
649 return oslTranslateFileError(ENAMETOOLONG
);
651 ustrchrcat('/', path_resolved_so_far
);
655 else // any other character
657 if ((presolvedsf
= ustrtoend(path_resolved_so_far
)) > sentinel
)
658 return oslTranslateFileError(ENAMETOOLONG
);
660 ustrchrcat(*punresolved
++, path_resolved_so_far
);
662 if (*punresolved
== '\0' && !realpath_failed
)
664 ferr
= _osl_resolvepath(
665 path_resolved_so_far
,
668 if (ferr
!= osl_File_E_None
)
674 sal_Int32 len
= rtl_ustr_getLength(path_resolved_so_far
);
676 OSL_ASSERT(len
< PATH_MAX
);
678 resolved_path
= OUString(path_resolved_so_far
, len
);
680 return osl_File_E_None
;
685 oslFileError
osl_getAbsoluteFileURL(
686 rtl_uString
* ustrBaseDirURL
,
687 rtl_uString
* ustrRelativeURL
,
688 rtl_uString
** pustrAbsoluteURL
)
690 /* Work around the below call to getSystemPathFromFileURL rejecting input
691 that starts with "/" (for whatever reason it behaves that way; but
692 changing that would start to break lots of tests at least) */
693 OUString
relUrl(ustrRelativeURL
);
694 if (relUrl
.startsWith("//"))
695 relUrl
= "file:" + relUrl
;
696 else if (relUrl
.startsWith("/"))
697 relUrl
= "file://" + relUrl
;
699 OUString unresolved_path
;
701 FileBase::RC frc
= FileBase::getSystemPathFromFileURL(relUrl
, unresolved_path
);
702 if (frc
!= FileBase::E_None
)
703 return oslFileError(frc
);
705 if (systemPathIsRelativePath(unresolved_path
))
708 oslFileError rc
= getSystemPathFromFileURL_Ex(ustrBaseDirURL
, &base_path
.pData
);
709 if (rc
!= osl_File_E_None
)
712 unresolved_path
= systemPathMakeAbsolutePath(base_path
, unresolved_path
);
715 OUString resolved_path
;
716 oslFileError rc
= osl_getAbsoluteFileURL_impl_(unresolved_path
, resolved_path
);
717 if (rc
== osl_File_E_None
)
719 rc
= osl_getFileURLFromSystemPath(resolved_path
.pData
, pustrAbsoluteURL
);
720 OSL_ASSERT(osl_File_E_None
== rc
);
726 namespace osl::detail
{
729 No separate error code if unicode to text conversion or getenv fails because for the
730 caller there is no difference why a file could not be found in $PATH
732 bool find_in_PATH(const OUString
& file_path
, OUString
& result
)
735 OUString
path("PATH");
738 if (osl_getEnvironment(path
.pData
, &env_path
.pData
) == osl_Process_E_None
)
739 bfound
= osl::searchPath(file_path
, env_path
, result
);
748 No separate error code if unicode to text conversion or getcwd fails because for the
749 caller there is no difference why a file could not be found in CDW
751 bool find_in_CWD(const OUString
& file_path
, OUString
& result
)
756 if (osl_getProcessWorkingDir(&cwd_url
.pData
) == osl_Process_E_None
)
759 FileBase::getSystemPathFromFileURL(cwd_url
, cwd
);
760 bfound
= osl::searchPath(file_path
, cwd
, result
);
765 bool find_in_searchPath(const OUString
& file_path
, rtl_uString
* search_path
, OUString
& result
)
767 return (search_path
&& osl::searchPath(file_path
, OUString(search_path
), result
));
772 oslFileError
osl_searchFileURL(rtl_uString
* ustrFilePath
, rtl_uString
* ustrSearchPath
, rtl_uString
** pustrURL
)
774 OSL_PRECOND(ustrFilePath
&& pustrURL
, "osl_searchFileURL: invalid parameter");
779 // try to interpret search path as file url else assume it's a system path list
780 rc
= FileBase::getSystemPathFromFileURL(ustrFilePath
, file_path
);
781 if (rc
== FileBase::E_INVAL
)
782 file_path
= ustrFilePath
;
783 else if (rc
!= FileBase::E_None
)
784 return oslFileError(rc
);
789 if (find_in_searchPath(file_path
, ustrSearchPath
, result
) ||
790 osl::detail::find_in_PATH(file_path
, result
) ||
791 find_in_CWD(file_path
, result
))
795 if (osl::realpath(result
, resolved
))
797 oslFileError osl_error
= osl_getFileURLFromSystemPath(resolved
.pData
, pustrURL
);
798 SAL_WARN_IF(osl_File_E_None
!= osl_error
, "sal.file", "osl_getFileURLFromSystemPath failed");
802 return bfound
? osl_File_E_None
: osl_File_E_NOENT
;
805 oslFileError
FileURLToPath(char * buffer
, size_t bufLen
, rtl_uString
* ustrFileURL
)
807 OString strSystemPath
;
808 oslFileError osl_error
= osl::detail::convertUrlToPathname(
809 OUString::unacquired(&ustrFileURL
), &strSystemPath
);
811 if(osl_error
!= osl_File_E_None
)
814 osl_systemPathRemoveSeparator(strSystemPath
.pData
);
816 if (o3tl::make_unsigned(strSystemPath
.getLength()) >= bufLen
) {
817 return osl_File_E_OVERFLOW
;
819 std::strcpy(buffer
, strSystemPath
.getStr());
824 int UnicodeToText( char * buffer
, size_t bufLen
, const sal_Unicode
* uniText
, sal_Int32 uniTextLen
)
826 sal_uInt32 nInfo
= 0;
827 sal_Size nSrcChars
= 0;
829 sal_Size nDestBytes
= UnicodeToTextConverter_Impl::getInstance().convert (
830 uniText
, uniTextLen
, buffer
, bufLen
,
831 OUSTRING_TO_OSTRING_CVTFLAGS
| RTL_UNICODETOTEXT_FLAGS_FLUSH
, &nInfo
, &nSrcChars
);
833 if( nInfo
& RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL
)
839 /* ensure trailing '\0' */
840 buffer
[nDestBytes
] = '\0';
846 class TextToUnicodeConverter_Impl
848 rtl_TextToUnicodeConverter m_converter
;
850 TextToUnicodeConverter_Impl()
851 : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
854 ~TextToUnicodeConverter_Impl()
856 rtl_destroyTextToUnicodeConverter (m_converter
);
860 static TextToUnicodeConverter_Impl
& getInstance()
862 static TextToUnicodeConverter_Impl g_theConverter
;
863 return g_theConverter
;
867 char const * pSrcBuf
, sal_Size nSrcBytes
, sal_Unicode
* pDstBuf
, sal_Size nDstChars
,
868 sal_uInt32 nFlags
, sal_uInt32
* pInfo
, sal_Size
* pSrcCvtBytes
)
870 OSL_ASSERT(m_converter
!= nullptr);
871 return rtl_convertTextToUnicode (
872 m_converter
, nullptr, pSrcBuf
, nSrcBytes
, pDstBuf
, nDstChars
, nFlags
, pInfo
, pSrcCvtBytes
);
879 size_t text_buffer_size
,
880 sal_Unicode
* unic_text
,
881 sal_Int32 unic_text_buffer_size
)
883 sal_uInt32 nInfo
= 0;
884 sal_Size nSrcChars
= 0;
886 sal_Size nDestBytes
= TextToUnicodeConverter_Impl::getInstance().convert(
887 text
, text_buffer_size
, unic_text
, unic_text_buffer_size
,
888 OSTRING_TO_OUSTRING_CVTFLAGS
| RTL_TEXTTOUNICODE_FLAGS_FLUSH
, &nInfo
, &nSrcChars
);
890 if (nInfo
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
)
896 /* ensure trailing '\0' */
897 unic_text
[nDestBytes
] = '\0';
901 oslFileError
osl::detail::convertUrlToPathname(OUString
const & url
, OString
* pathname
) {
902 assert(pathname
!= nullptr);
905 e
= getSystemPathFromFileUrl(url
, pathname
, true);
906 } catch (std::length_error
&) {
907 e
= osl_File_E_RANGE
;
909 if (e
== osl_File_E_None
&& !pathname
->startsWith("/")) {
910 e
= osl_File_E_INVAL
;
915 oslFileError
osl::detail::convertPathnameToUrl(OString
const & pathname
, OUString
* url
) {
916 assert(url
!= nullptr);
917 OUStringBuffer
buf(10+pathname
.getLength());
919 if (pathname
.startsWith("/")) {
921 // so if pathname should ever start with "//" that isn't mistaken for an authority
924 for (sal_Size convert
= pathname
.getLength();;) {
925 auto n
= std::max(convert
, sal_Size(PATH_MAX
)); // approximation of required converted size
926 OUStringBuffer
ubuf(static_cast<int>(n
));
927 auto s
= ubuf
.appendUninitialized(n
);
930 //TODO: context, for reliable treatment of DESTBUFFERTOSMALL:
931 n
= TextToUnicodeConverter_Impl::getInstance().convert(
932 pathname
.getStr() + pathname
.getLength() - convert
, convert
, s
, n
,
933 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
934 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
| RTL_TEXTTOUNICODE_FLAGS_FLUSH
),
939 ubuf
.makeStringAndClear(), uriCharClass
.data(), rtl_UriEncodeIgnoreEscapes
,
940 RTL_TEXTENCODING_UTF8
));
941 assert(converted
<= convert
);
942 convert
-= converted
;
943 if ((info
& RTL_TEXTTOUNICODE_INFO_ERROR
) != 0) {
945 //TODO: see writeEscapeOctet in sal/rtl/uri.cxx
947 unsigned char c
= pathname
[pathname
.getLength() - convert
];
949 static sal_Unicode
const aHex
[16]
950 = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
951 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; /* '0'--'9', 'A'--'F' */
952 buf
.append(OUStringChar(aHex
[c
>> 4]) + OUStringChar(aHex
[c
& 15]));
956 assert((convert
== 0) == ((info
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
) == 0));
957 if ((info
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
) == 0) {
961 *url
= buf
.makeStringAndClear();
962 return osl_File_E_None
;
965 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */