Bump for 3.6-28
[LibreOffice.git] / sal / osl / unx / file_url.cxx
blob7addb8e00d24717471baa293807a6317c195411e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
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.
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).
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.
27 ************************************************************************/
30 #include "file_url.h"
32 #include "system.h"
34 #include <limits.h>
35 #include <errno.h>
36 #include <strings.h>
37 #include <unistd.h>
39 #include "osl/file.hxx"
40 #include <osl/security.hxx>
41 #include <osl/diagnose.h>
42 #include <osl/thread.h>
43 #include <osl/process.h>
45 #include <rtl/uri.hxx>
46 #include <rtl/ustring.hxx>
47 #include <rtl/ustrbuf.h>
48 #include "rtl/textcvt.h"
50 #include "file_error_transl.h"
51 #include "file_path_helper.hxx"
53 #include "uunxapi.hxx"
55 /***************************************************
57 General note
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 independend, 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 an URI parser etc.
66 so this code should be consolidated.
68 **************************************************/
69 /************************************************************************
70 * ToDo
72 * Fix osl_getCanonicalName
74 ***********************************************************************/
77 /***************************************************
78 * namespace directives
79 **************************************************/
81 using namespace osl;
83 /***************************************************
84 * constants
85 **************************************************/
87 const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/');
88 const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':');
89 const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.');
91 /******************************************************************************
93 * Exported Module Functions
95 *****************************************************************************/
97 /* a slightly modified version of Pchar in rtl/source/uri.c */
98 const sal_Bool uriCharClass[128] =
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */
103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
105 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
106 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
107 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */
111 /* check for top wrong usage strings */
113 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
115 rtl_uString *pTmp = NULL;
116 sal_Bool bRet;
118 rtl_uString_newFromStr_WithLength( &pTmp, path, len );
120 rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
122 bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
123 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
124 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
125 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
126 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
128 rtl_uString_release( pTmp );
129 return bRet;
133 /****************************************************************************/
134 /* osl_getCanonicalName */
135 /****************************************************************************/
137 oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL )
139 OSL_FAIL("osl_getCanonicalName not implemented");
141 rtl_uString_newFromString(pustrValidURL, ustrFileURL);
142 return osl_File_E_None;
145 /****************************************************************************/
146 /* osl_getSystemPathFromFileURL */
147 /****************************************************************************/
149 namespace {
151 oslFileError getSystemPathFromFileUrl(
152 rtl::OUString const & url, rtl::OUString * path, bool homeAbbreviation)
154 OSL_ASSERT(path != 0 && path->isEmpty());
156 sal_Unicode const * p = url.getStr();
157 sal_Unicode const * end = p + url.getLength();
159 /* a valid file url may not start with '/' */
160 if ((p == end) || (*p == UNICHAR_SLASH))
161 return osl_File_E_INVAL;
163 for (sal_Unicode const * p1 = p; p1 != end; ++p1) {
164 if (*p1 == '?' || *p1 == '#' ||
165 (*p1 == '%' && end - p1 >= 3 && p1[1] == '2' &&
166 (p1[2] == 'F' || p1[2] == 'f')))
168 return osl_File_E_INVAL;
171 sal_Unicode const * p1 = p;
172 while (p1 != end && *p1 != ':' && *p1 != '/') {
173 ++p1;
175 if (p1 != end && *p1 == ':') {
176 if (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
177 p, p1 - p, RTL_CONSTASCII_STRINGPARAM("file")) !=
180 return osl_File_E_INVAL;
182 p = p1 + 1;
184 if (end - p >= 2 && p[0] == '/' && p[1] == '/') {
185 p += 2;
186 sal_Int32 i = rtl_ustr_indexOfChar_WithLength(p, end - p, '/');
187 p1 = i < 0 ? end : p + i;
188 if (p1 != p &&
189 (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
190 p, p1 - p, RTL_CONSTASCII_STRINGPARAM("localhost")) !=
191 0) &&
192 rtl_ustr_ascii_compare_WithLength(p, p1 - p, "127.0.0.1") != 0)
194 return osl_File_E_INVAL;
196 p = p1;
197 if (p == end) {
198 *path = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
199 return osl_File_E_None;
202 if (homeAbbreviation && end - p >= 2 && p[0] == '/' && p[1] == '~') {
203 p += 2;
204 sal_Int32 i = rtl_ustr_indexOfChar_WithLength(p, end - p, '/');
205 p1 = i < 0 ? end : p + i;
206 if (p1 == p) {
207 rtl::OUString home;
208 if (!osl::Security().getHomeDir(home)) {
209 return osl_File_E_INVAL;
211 oslFileError e = getSystemPathFromFileUrl(home, path, false);
212 if (e != osl_File_E_None) {
213 return e;
215 } else {
216 return osl_File_E_INVAL; //TODO
218 p = p1;
220 rtl::OUString d(
221 rtl::Uri::decode(
222 rtl::OUString(p, end - p), rtl_UriDecodeWithCharset,
223 RTL_TEXTENCODING_UTF8));
224 if (d.indexOf(0) >=0) {
225 return osl_File_E_INVAL;
227 *path += d;
228 return osl_File_E_None;
232 oslFileError osl_getSystemPathFromFileURL(
233 rtl_uString * pustrFileURL, rtl_uString ** ppustrSystemPath)
235 rtl::OUString p;
236 oslFileError e = getSystemPathFromFileUrl(
237 rtl::OUString(pustrFileURL), &p, true);
238 if (e == osl_File_E_None) {
239 rtl_uString_assign(ppustrSystemPath, p.pData);
241 return e;
244 /****************************************************************************/
245 /* osl_getFileURLFromSystemPath */
246 /****************************************************************************/
248 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
250 static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
252 rtl_uString *pTmp = NULL;
253 sal_Int32 nIndex;
255 if( 0 == ustrSystemPath->length )
256 return osl_File_E_INVAL;
258 /* temporary hack: if already file url, return ustrSystemPath */
260 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
263 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
265 OSL_FAIL( "osl_getFileURLFromSystemPath: input is already file URL" );
266 rtl_uString_assign( pustrFileURL, ustrSystemPath );
268 else
270 rtl_uString *pTmp2 = NULL;
272 OSL_FAIL( "osl_getFileURLFromSystemPath: input is wrong file URL" );
273 rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
274 rtl_uString_newFromAscii( &pTmp2, "file://" );
275 rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
276 rtl_uString_release( pTmp2 );
278 return osl_File_E_None;
280 return osl_File_E_INVAL;
284 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
285 if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
287 /* check if another user is specified */
288 if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
290 /* osl_getHomeDir returns file URL */
291 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );
293 /* remove "file://" prefix */
294 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
296 /* replace '~' in original string */
297 rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
300 else
302 /* FIXME: replace ~user with users home directory */
303 return osl_File_E_INVAL;
307 /* check if initial string contains double instances of '/' */
308 nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
309 if( -1 != nIndex )
311 sal_Int32 nSrcIndex;
312 sal_Int32 nDeleted = 0;
314 /* if pTmp is not already allocated, copy ustrSystemPath for modification */
315 if( NULL == pTmp )
316 rtl_uString_newFromString( &pTmp, ustrSystemPath );
318 /* adapt index to pTmp */
319 nIndex += pTmp->length - ustrSystemPath->length;
321 /* remove all occurrences of '//' */
322 for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
324 if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
325 nDeleted++;
326 else
327 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
330 /* adjust length member */
331 pTmp->length -= nDeleted;
334 if( NULL == pTmp )
335 rtl_uString_assign( &pTmp, ustrSystemPath );
337 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
339 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
342 /* file URLs must be URI encoded */
343 rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
345 rtl_uString_release( pTmp );
347 /* absolute urls should start with 'file://' */
348 if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
350 rtl_uString *pProtocol = NULL;
352 rtl_uString_newFromAscii( &pProtocol, "file://" );
353 rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
354 rtl_uString_release( pProtocol );
357 return osl_File_E_None;
360 /****************************************************************************
361 * osl_getSystemPathFromFileURL_Ex - helper function
362 * clients may specify if they want to accept relative
363 * URLs or not
364 ****************************************************************************/
366 oslFileError osl_getSystemPathFromFileURL_Ex(
367 rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
369 rtl_uString* temp = 0;
370 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
372 if (osl_File_E_None == osl_error)
374 if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0]))
376 *pustrSystemPath = temp;
378 else
380 rtl_uString_release(temp);
381 osl_error = osl_File_E_INVAL;
385 return osl_error;
388 namespace /* private */
391 /******************************************************
392 * Helper function, return a pinter to the final '\0'
393 * of a string
394 ******************************************************/
396 sal_Unicode* ustrtoend(sal_Unicode* pStr)
398 return (pStr + rtl_ustr_getLength(pStr));
401 /*********************************************
403 ********************************************/
405 sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
407 sal_Unicode* p = ustrtoend(d);
408 *p++ = chr;
409 *p = 0;
410 return d;
413 /******************************************************
415 ******************************************************/
417 bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
419 sal_Unicode* p = ustrtoend(pStr);
420 if (p > pStr)
421 p--;
422 return (*p == Chr);
425 /******************************************************
426 * Remove the last part of a path, a path that has
427 * only a '/' or no '/' at all will be returned
428 * unmodified
429 ******************************************************/
431 sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
433 /* we always may skip -2 because we
434 may at least stand on a '/' but
435 either there is no other character
436 before this '/' or it's another
437 character than the '/'
439 sal_Unicode* p = ustrtoend(aPath) - 2;
441 // move back to the next path separator
442 // or to the start of the string
443 while ((p > aPath) && (*p != UNICHAR_SLASH))
444 p--;
446 if (p >= aPath)
448 if (UNICHAR_SLASH == *p)
450 p++;
451 *p = '\0';
453 else
455 *p = '\0';
459 return aPath;
462 /******************************************************
464 ******************************************************/
466 oslFileError _osl_resolvepath(
467 /*inout*/ sal_Unicode* path,
468 /*inout*/ bool* failed)
470 oslFileError ferr = osl_File_E_None;
472 if (!*failed)
474 char unresolved_path[PATH_MAX];
475 if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
476 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
478 char resolved_path[PATH_MAX];
479 if (realpath(unresolved_path, resolved_path))
481 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
482 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
485 else
487 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
488 *failed = true;
489 else
490 ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
494 return ferr;
497 /******************************************************
498 * Works even with non existing paths. The resulting
499 * path must not exceed PATH_MAX else
500 * osl_File_E_NAMETOOLONG is the result
501 ******************************************************/
503 oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
505 // the given unresolved path must not exceed PATH_MAX
506 if (unresolved_path.getLength() >= (PATH_MAX - 2))
507 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
509 sal_Unicode path_resolved_so_far[PATH_MAX];
510 const sal_Unicode* punresolved = unresolved_path.getStr();
511 sal_Unicode* presolvedsf = path_resolved_so_far;
513 // reserve space for leading '/' and trailing '\0'
514 // do not exceed this limit
515 sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
517 // if realpath fails with error ENOTDIR, EACCES or ENOENT
518 // we will not call it again, because _osl_realpath should also
519 // work with non existing directories etc.
520 bool realpath_failed = false;
521 oslFileError ferr;
523 path_resolved_so_far[0] = '\0';
525 while (*punresolved != '\0')
527 // ignore '/.' , skip one part back when '/..'
529 if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
531 if ('\0' == *(punresolved + 1))
533 punresolved++;
534 continue;
536 else if (UNICHAR_SLASH == *(punresolved + 1))
538 punresolved += 2;
539 continue;
541 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
543 _rmlastpathtoken(path_resolved_so_far);
545 presolvedsf = ustrtoend(path_resolved_so_far) - 1;
547 if (UNICHAR_SLASH == *(punresolved + 2))
548 punresolved += 3;
549 else
550 punresolved += 2;
552 continue;
554 else // a file or directory name may start with '.'
556 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
557 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
559 ustrchrcat(*punresolved++, path_resolved_so_far);
561 if ('\0' == *punresolved && !realpath_failed)
563 ferr = _osl_resolvepath(
564 path_resolved_so_far,
565 &realpath_failed);
567 if (osl_File_E_None != ferr)
568 return ferr;
572 else if (UNICHAR_SLASH == *punresolved)
574 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
575 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
577 ustrchrcat(*punresolved++, path_resolved_so_far);
579 if (!realpath_failed)
581 ferr = _osl_resolvepath(
582 path_resolved_so_far,
583 &realpath_failed);
585 if (osl_File_E_None != ferr)
586 return ferr;
588 if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
590 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
591 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
593 ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
597 else // any other character
599 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
600 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
602 ustrchrcat(*punresolved++, path_resolved_so_far);
604 if ('\0' == *punresolved && !realpath_failed)
606 ferr = _osl_resolvepath(
607 path_resolved_so_far,
608 &realpath_failed);
610 if (osl_File_E_None != ferr)
611 return ferr;
616 sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
618 OSL_ASSERT(len < PATH_MAX);
620 resolved_path = rtl::OUString(path_resolved_so_far, len);
622 return osl_File_E_None;
625 } // end namespace private
628 /******************************************************
629 * osl_getAbsoluteFileURL
630 ******************************************************/
632 oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
634 FileBase::RC rc;
635 rtl::OUString unresolved_path;
636 static char *allow_symlinks = getenv( "SAL_ALLOW_LINKOO_SYMLINKS" );
638 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
640 if(FileBase::E_None != rc)
641 return oslFileError(rc);
643 if (systemPathIsRelativePath(unresolved_path))
645 rtl::OUString base_path;
646 rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
648 if (FileBase::E_None != rc)
649 return oslFileError(rc);
651 rtl::OUString abs_path;
652 systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
654 unresolved_path = abs_path;
657 rtl::OUString resolved_path;
659 if (!allow_symlinks)
661 rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
663 else
665 // SAL_ALLOW_LINKOO_SYMLINKS environment variable:
666 // for linkoo to work, we need to let the symlinks to the libraries untouched
667 rtl::OUString base;
668 sal_Int32 last_slash = unresolved_path.lastIndexOf( UNICHAR_SLASH );
670 if (last_slash >= 0 && last_slash + 1 < unresolved_path.getLength()
671 && ! ( last_slash + 2 == unresolved_path.getLength() && unresolved_path.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("."), last_slash + 1) )
672 && ! ( last_slash + 3 == unresolved_path.getLength() && unresolved_path.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(".."), last_slash + 1) ))
674 base = unresolved_path.copy(last_slash+1);
675 unresolved_path = unresolved_path.copy(0, last_slash);
678 rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
680 if (!base.isEmpty())
682 resolved_path += rtl::OUString( UNICHAR_SLASH );
683 resolved_path += base;
687 if (FileBase::E_None == rc)
689 rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
690 OSL_ASSERT(FileBase::E_None == rc);
693 return oslFileError(rc);
697 namespace /* private */
700 /*********************************************
701 No separate error code if unicode to text
702 conversion or getenv fails because for the
703 caller there is no difference why a file
704 could not be found in $PATH
705 ********************************************/
707 bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
709 bool bfound = false;
710 rtl::OUString path(RTL_CONSTASCII_USTRINGPARAM("PATH"));
711 rtl::OUString env_path;
713 if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
714 bfound = osl::searchPath(file_path, env_path, result);
716 return bfound;
719 /*********************************************
720 No separate error code if unicode to text
721 conversion or getcwd fails because for the
722 caller there is no difference why a file
723 could not be found in CDW
724 ********************************************/
726 bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
728 bool bfound = false;
729 rtl::OUString cwd_url;
731 if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
733 rtl::OUString cwd;
734 FileBase::getSystemPathFromFileURL(cwd_url, cwd);
735 bfound = osl::searchPath(file_path, cwd, result);
737 return bfound;
740 /*********************************************
742 ********************************************/
744 bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
746 return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
749 } // end namespace private
752 /****************************************************************************
753 * osl_searchFileURL
754 ***************************************************************************/
756 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
758 OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
760 FileBase::RC rc;
761 rtl::OUString file_path;
763 // try to interpret search path as file url else assume it's a system path list
764 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
765 if (FileBase::E_INVAL == rc)
766 file_path = ustrFilePath;
767 else if (FileBase::E_None != rc)
768 return oslFileError(rc);
770 bool bfound = false;
771 rtl::OUString result;
773 if (find_in_searchPath(file_path, ustrSearchPath, result) ||
774 find_in_PATH(file_path, result) ||
775 find_in_CWD(file_path, result))
777 rtl::OUString resolved;
779 if (osl::realpath(result, resolved))
781 #if OSL_DEBUG_LEVEL > 0
782 oslFileError osl_error =
783 #endif
784 osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
785 OSL_ASSERT(osl_File_E_None == osl_error);
786 bfound = true;
789 return bfound ? osl_File_E_None : osl_File_E_NOENT;
793 /****************************************************************************
794 * FileURLToPath
795 ***************************************************************************/
797 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
799 rtl_uString* ustrSystemPath = NULL;
800 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
802 if(osl_File_E_None != osl_error)
803 return osl_error;
805 osl_systemPathRemoveSeparator(ustrSystemPath);
807 /* convert unicode path to text */
808 if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
809 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
811 rtl_uString_release(ustrSystemPath);
813 return osl_error;
816 /*****************************************************************************
817 * UnicodeToText
818 ****************************************************************************/
820 namespace /* private */
822 class UnicodeToTextConverter_Impl
824 rtl_UnicodeToTextConverter m_converter;
826 UnicodeToTextConverter_Impl()
827 : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
830 ~UnicodeToTextConverter_Impl()
832 rtl_destroyUnicodeToTextConverter (m_converter);
834 public:
835 static UnicodeToTextConverter_Impl & getInstance()
837 static UnicodeToTextConverter_Impl g_theConverter;
838 return g_theConverter;
841 sal_Size convert(
842 sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
843 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
845 OSL_ASSERT(m_converter != 0);
846 return rtl_convertUnicodeToText (
847 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
850 } // end namespace private
852 int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
854 sal_uInt32 nInfo = 0;
855 sal_Size nSrcChars = 0;
857 sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
858 uniText, uniTextLen, buffer, bufLen,
859 OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
861 if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
863 errno = EOVERFLOW;
864 return 0;
867 /* ensure trailing '\0' */
868 buffer[nDestBytes] = '\0';
869 return nDestBytes;
872 /*****************************************************************************
873 * TextToUnicode
874 ****************************************************************************/
876 namespace /* private */
878 class TextToUnicodeConverter_Impl
880 rtl_TextToUnicodeConverter m_converter;
882 TextToUnicodeConverter_Impl()
883 : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
886 ~TextToUnicodeConverter_Impl()
888 rtl_destroyTextToUnicodeConverter (m_converter);
891 public:
892 static TextToUnicodeConverter_Impl & getInstance()
894 static TextToUnicodeConverter_Impl g_theConverter;
895 return g_theConverter;
898 sal_Size convert(
899 sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
900 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
902 OSL_ASSERT(m_converter != 0);
903 return rtl_convertTextToUnicode (
904 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
907 } // end namespace private
909 int TextToUnicode(
910 const char* text,
911 size_t text_buffer_size,
912 sal_Unicode* unic_text,
913 sal_Int32 unic_text_buffer_size)
915 sal_uInt32 nInfo = 0;
916 sal_Size nSrcChars = 0;
918 sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
919 text, text_buffer_size, unic_text, unic_text_buffer_size,
920 OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
922 if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
924 errno = EOVERFLOW;
925 return 0;
928 /* ensure trailing '\0' */
929 unic_text[nDestBytes] = '\0';
930 return nDestBytes;
933 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */