Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/DirectoryHelper.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 */
9
10
#include <comphelper/DirectoryHelper.hxx>
11
12
#include <sal/config.h>
13
#include <osl/file.hxx>
14
#include <rtl/uri.hxx>
15
16
#include <memory>
17
18
namespace comphelper
19
{
20
typedef std::shared_ptr<osl::File> FileSharedPtr;
21
22
std::u16string_view DirectoryHelper::splitAtLastToken(std::u16string_view rSrc, sal_Unicode aToken,
23
                                                      OUString& rRight)
24
0
{
25
0
    const size_t nIndex(rSrc.rfind(aToken));
26
0
    std::u16string_view aRetval;
27
28
0
    if (std::u16string_view::npos == nIndex)
29
0
    {
30
0
        aRetval = rSrc;
31
0
        rRight.clear();
32
0
    }
33
0
    else if (nIndex > 0)
34
0
    {
35
0
        aRetval = rSrc.substr(0, nIndex);
36
37
0
        if (rSrc.size() > nIndex + 1)
38
0
        {
39
0
            rRight = rSrc.substr(nIndex + 1);
40
0
        }
41
0
    }
42
43
0
    return aRetval;
44
0
}
45
46
bool DirectoryHelper::fileExists(const OUString& rBaseURL)
47
0
{
48
0
    if (!rBaseURL.isEmpty())
49
0
    {
50
0
        FileSharedPtr aBaseFile = std::make_shared<osl::File>(rBaseURL);
51
52
0
        return (osl::File::E_None == aBaseFile->open(osl_File_OpenFlag_Read));
53
0
    }
54
55
0
    return false;
56
0
}
57
58
bool DirectoryHelper::dirExists(const OUString& rDirURL)
59
0
{
60
0
    if (!rDirURL.isEmpty())
61
0
    {
62
0
        osl::Directory aDirectory(rDirURL);
63
64
0
        return (osl::FileBase::E_None == aDirectory.open());
65
0
    }
66
67
0
    return false;
68
0
}
69
70
void DirectoryHelper::scanDirsAndFiles(const OUString& rDirURL, std::set<OUString>& rDirs,
71
                                       std::set<std::pair<OUString, OUString>>& rFiles)
72
9.16k
{
73
9.16k
    if (rDirURL.isEmpty())
74
0
        return;
75
76
9.16k
    osl::Directory aDirectory(rDirURL);
77
78
9.16k
    if (osl::FileBase::E_None != aDirectory.open())
79
0
        return;
80
81
9.16k
    auto lcl_encodeUriSegment = [](OUString const& rPath) {
82
0
        return rtl::Uri::encode(rPath, rtl_UriCharClassUricNoSlash, rtl_UriEncodeIgnoreEscapes,
83
0
                                RTL_TEXTENCODING_UTF8);
84
0
    };
85
86
9.16k
    osl::DirectoryItem aDirectoryItem;
87
88
9.16k
    while (osl::FileBase::E_None == aDirectory.getNextItem(aDirectoryItem))
89
0
    {
90
0
        osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName);
91
92
0
        if (osl::FileBase::E_None == aDirectoryItem.getFileStatus(aFileStatus))
93
0
        {
94
0
            if (aFileStatus.isDirectory())
95
0
            {
96
0
                const OUString aFileName(aFileStatus.getFileName());
97
98
0
                if (!aFileName.isEmpty())
99
0
                {
100
0
                    rDirs.insert(lcl_encodeUriSegment(aFileName));
101
0
                }
102
0
            }
103
0
            else if (aFileStatus.isRegular())
104
0
            {
105
0
                OUString aFileName(aFileStatus.getFileName());
106
0
                OUString aExtension;
107
0
                aFileName = splitAtLastToken(aFileName, '.', aExtension);
108
109
0
                if (!aFileName.isEmpty())
110
0
                {
111
0
                    rFiles.insert(std::pair<OUString, OUString>(lcl_encodeUriSegment(aFileName),
112
0
                                                                lcl_encodeUriSegment(aExtension)));
113
0
                }
114
0
            }
115
0
        }
116
0
    }
117
9.16k
}
118
119
bool DirectoryHelper::deleteDirRecursively(const OUString& rDirURL)
120
9.16k
{
121
9.16k
    std::set<OUString> aDirs;
122
9.16k
    std::set<std::pair<OUString, OUString>> aFiles;
123
9.16k
    bool bError(false);
124
125
9.16k
    scanDirsAndFiles(rDirURL, aDirs, aFiles);
126
127
9.16k
    for (const auto& dir : aDirs)
128
0
    {
129
0
        const OUString aNewDirURL(rDirURL + "/" + dir);
130
131
0
        bError |= deleteDirRecursively(aNewDirURL);
132
0
    }
133
134
9.16k
    for (const auto& file : aFiles)
135
0
    {
136
0
        OUString aNewFileURL(rDirURL + "/" + file.first);
137
138
0
        if (!file.second.isEmpty())
139
0
        {
140
0
            aNewFileURL += "." + file.second;
141
0
        }
142
0
        bError |= (osl::FileBase::E_None != osl::File::remove(aNewFileURL));
143
0
    }
144
145
9.16k
    bError |= (osl::FileBase::E_None != osl::Directory::remove(rDirURL));
146
147
9.16k
    return bError;
148
9.16k
}
149
150
// both exist, move content
151
bool DirectoryHelper::moveDirContent(const OUString& rSourceDirURL,
152
                                     std::u16string_view rTargetDirURL,
153
                                     const std::set<OUString>& rExcludeList)
154
0
{
155
0
    std::set<OUString> aDirs;
156
0
    std::set<std::pair<OUString, OUString>> aFiles;
157
0
    bool bError(false);
158
159
0
    scanDirsAndFiles(rSourceDirURL, aDirs, aFiles);
160
161
0
    for (const auto& dir : aDirs)
162
0
    {
163
0
        const bool bExcluded(!rExcludeList.empty() && rExcludeList.find(dir) != rExcludeList.end());
164
165
0
        if (!bExcluded)
166
0
        {
167
0
            const OUString aNewSourceDirURL(rSourceDirURL + "/" + dir);
168
169
0
            if (dirExists(aNewSourceDirURL))
170
0
            {
171
0
                const OUString aNewTargetDirURL(OUString::Concat(rTargetDirURL) + "/" + dir);
172
173
0
                if (dirExists(aNewTargetDirURL))
174
0
                {
175
0
                    deleteDirRecursively(aNewTargetDirURL);
176
0
                }
177
178
0
                bError |= (osl::FileBase::E_None
179
0
                           != osl::File::move(aNewSourceDirURL, aNewTargetDirURL));
180
0
            }
181
0
        }
182
0
    }
183
184
0
    for (const auto& file : aFiles)
185
0
    {
186
0
        OUString aSourceFileURL(rSourceDirURL + "/" + file.first);
187
188
0
        if (!file.second.isEmpty())
189
0
        {
190
0
            aSourceFileURL += "." + file.second;
191
0
        }
192
193
0
        if (fileExists(aSourceFileURL))
194
0
        {
195
0
            OUString aTargetFileURL(OUString::Concat(rTargetDirURL) + "/" + file.first);
196
197
0
            if (!file.second.isEmpty())
198
0
            {
199
0
                aTargetFileURL += "." + file.second;
200
0
            }
201
202
0
            if (fileExists(aTargetFileURL))
203
0
            {
204
0
                osl::File::remove(aTargetFileURL);
205
0
            }
206
207
0
            bError |= (osl::FileBase::E_None != osl::File::move(aSourceFileURL, aTargetFileURL));
208
0
        }
209
0
    }
210
211
0
    return bError;
212
0
}
213
}