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/.
10 #include <comphelper/DirectoryHelper.hxx>
12 #include <sal/config.h>
13 #include <osl/file.hxx>
14 #include <rtl/uri.hxx>
20 typedef std::shared_ptr
<osl::File
> FileSharedPtr
;
22 std::u16string_view
DirectoryHelper::splitAtLastToken(std::u16string_view rSrc
, sal_Unicode aToken
,
25 const size_t nIndex(rSrc
.rfind(aToken
));
26 std::u16string_view aRetval
;
28 if (std::u16string_view::npos
== nIndex
)
35 aRetval
= rSrc
.substr(0, nIndex
);
37 if (rSrc
.size() > nIndex
+ 1)
39 rRight
= rSrc
.substr(nIndex
+ 1);
46 bool DirectoryHelper::fileExists(const OUString
& rBaseURL
)
48 if (!rBaseURL
.isEmpty())
50 FileSharedPtr aBaseFile
= std::make_shared
<osl::File
>(rBaseURL
);
52 return (osl::File::E_None
== aBaseFile
->open(osl_File_OpenFlag_Read
));
58 bool DirectoryHelper::dirExists(const OUString
& rDirURL
)
60 if (!rDirURL
.isEmpty())
62 osl::Directory
aDirectory(rDirURL
);
64 return (osl::FileBase::E_None
== aDirectory
.open());
70 void DirectoryHelper::scanDirsAndFiles(const OUString
& rDirURL
, std::set
<OUString
>& rDirs
,
71 std::set
<std::pair
<OUString
, OUString
>>& rFiles
)
73 if (rDirURL
.isEmpty())
76 osl::Directory
aDirectory(rDirURL
);
78 if (osl::FileBase::E_None
!= aDirectory
.open())
81 auto lcl_encodeUriSegment
= [](OUString
const& rPath
) {
82 return rtl::Uri::encode(rPath
, rtl_UriCharClassUricNoSlash
, rtl_UriEncodeIgnoreEscapes
,
83 RTL_TEXTENCODING_UTF8
);
86 osl::DirectoryItem aDirectoryItem
;
88 while (osl::FileBase::E_None
== aDirectory
.getNextItem(aDirectoryItem
))
90 osl::FileStatus
aFileStatus(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileName
);
92 if (osl::FileBase::E_None
== aDirectoryItem
.getFileStatus(aFileStatus
))
94 if (aFileStatus
.isDirectory())
96 const OUString
aFileName(aFileStatus
.getFileName());
98 if (!aFileName
.isEmpty())
100 rDirs
.insert(lcl_encodeUriSegment(aFileName
));
103 else if (aFileStatus
.isRegular())
105 OUString
aFileName(aFileStatus
.getFileName());
107 aFileName
= splitAtLastToken(aFileName
, '.', aExtension
);
109 if (!aFileName
.isEmpty())
111 rFiles
.insert(std::pair
<OUString
, OUString
>(lcl_encodeUriSegment(aFileName
),
112 lcl_encodeUriSegment(aExtension
)));
119 bool DirectoryHelper::deleteDirRecursively(const OUString
& rDirURL
)
121 std::set
<OUString
> aDirs
;
122 std::set
<std::pair
<OUString
, OUString
>> aFiles
;
125 scanDirsAndFiles(rDirURL
, aDirs
, aFiles
);
127 for (const auto& dir
: aDirs
)
129 const OUString
aNewDirURL(rDirURL
+ "/" + dir
);
131 bError
|= deleteDirRecursively(aNewDirURL
);
134 for (const auto& file
: aFiles
)
136 OUString
aNewFileURL(rDirURL
+ "/" + file
.first
);
138 if (!file
.second
.isEmpty())
140 aNewFileURL
+= "." + file
.second
;
142 bError
|= (osl::FileBase::E_None
!= osl::File::remove(aNewFileURL
));
145 bError
|= (osl::FileBase::E_None
!= osl::Directory::remove(rDirURL
));
150 // both exist, move content
151 bool DirectoryHelper::moveDirContent(const OUString
& rSourceDirURL
,
152 std::u16string_view rTargetDirURL
,
153 const std::set
<OUString
>& rExcludeList
)
155 std::set
<OUString
> aDirs
;
156 std::set
<std::pair
<OUString
, OUString
>> aFiles
;
159 scanDirsAndFiles(rSourceDirURL
, aDirs
, aFiles
);
161 for (const auto& dir
: aDirs
)
163 const bool bExcluded(!rExcludeList
.empty() && rExcludeList
.find(dir
) != rExcludeList
.end());
167 const OUString
aNewSourceDirURL(rSourceDirURL
+ "/" + dir
);
169 if (dirExists(aNewSourceDirURL
))
171 const OUString
aNewTargetDirURL(OUString::Concat(rTargetDirURL
) + "/" + dir
);
173 if (dirExists(aNewTargetDirURL
))
175 deleteDirRecursively(aNewTargetDirURL
);
178 bError
|= (osl::FileBase::E_None
179 != osl::File::move(aNewSourceDirURL
, aNewTargetDirURL
));
184 for (const auto& file
: aFiles
)
186 OUString
aSourceFileURL(rSourceDirURL
+ "/" + file
.first
);
188 if (!file
.second
.isEmpty())
190 aSourceFileURL
+= "." + file
.second
;
193 if (fileExists(aSourceFileURL
))
195 OUString
aTargetFileURL(OUString::Concat(rTargetDirURL
) + "/" + file
.first
);
197 if (!file
.second
.isEmpty())
199 aTargetFileURL
+= "." + file
.second
;
202 if (fileExists(aTargetFileURL
))
204 osl::File::remove(aTargetFileURL
);
207 bError
|= (osl::FileBase::E_None
!= osl::File::move(aSourceFileURL
, aTargetFileURL
));