18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "rofs_filesystem.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci#include <cstdint>
208bf80f4bSopenharmony_ci
218bf80f4bSopenharmony_ci#include <base/containers/allocator.h>
228bf80f4bSopenharmony_ci#include <base/containers/array_view.h>
238bf80f4bSopenharmony_ci#include <base/containers/iterator.h>
248bf80f4bSopenharmony_ci#include <base/containers/string.h>
258bf80f4bSopenharmony_ci#include <base/containers/string_view.h>
268bf80f4bSopenharmony_ci#include <base/containers/type_traits.h>
278bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h>
288bf80f4bSopenharmony_ci#include <base/containers/vector.h>
298bf80f4bSopenharmony_ci#include <base/namespace.h>
308bf80f4bSopenharmony_ci#include <core/io/intf_directory.h>
318bf80f4bSopenharmony_ci#include <core/io/intf_file.h>
328bf80f4bSopenharmony_ci#include <core/log.h>
338bf80f4bSopenharmony_ci#include <core/namespace.h>
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE()
368bf80f4bSopenharmony_cinamespace {
378bf80f4bSopenharmony_ciusing BASE_NS::array_view;
388bf80f4bSopenharmony_ciusing BASE_NS::CloneData;
398bf80f4bSopenharmony_ciusing BASE_NS::move;
408bf80f4bSopenharmony_ciusing BASE_NS::string;
418bf80f4bSopenharmony_ciusing BASE_NS::string_view;
428bf80f4bSopenharmony_ciusing BASE_NS::vector;
438bf80f4bSopenharmony_ci
448bf80f4bSopenharmony_cistruct FsEntry {
458bf80f4bSopenharmony_ci    const char fname[256];
468bf80f4bSopenharmony_ci    const uint64_t offset;
478bf80f4bSopenharmony_ci    const uint64_t size;
488bf80f4bSopenharmony_ci};
498bf80f4bSopenharmony_ci
508bf80f4bSopenharmony_ci/** Read-only memory file. */
518bf80f4bSopenharmony_ciclass ROFSMemoryFile final : public IFile {
528bf80f4bSopenharmony_cipublic:
538bf80f4bSopenharmony_ci    ~ROFSMemoryFile() override = default;
548bf80f4bSopenharmony_ci    ROFSMemoryFile(const uint8_t* const data, const size_t size) : data_(data), size_(size) {}
558bf80f4bSopenharmony_ci    ROFSMemoryFile(const ROFSMemoryFile&) = delete;
568bf80f4bSopenharmony_ci    ROFSMemoryFile(ROFSMemoryFile&&) = delete;
578bf80f4bSopenharmony_ci    ROFSMemoryFile& operator=(const ROFSMemoryFile&) = delete;
588bf80f4bSopenharmony_ci    ROFSMemoryFile& operator=(ROFSMemoryFile&&) = delete;
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_ci    Mode GetMode() const override
618bf80f4bSopenharmony_ci    {
628bf80f4bSopenharmony_ci        return IFile::Mode::READ_ONLY;
638bf80f4bSopenharmony_ci    }
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ci    void Close() override {}
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ci    uint64_t Read(void* buffer, uint64_t count) override
688bf80f4bSopenharmony_ci    {
698bf80f4bSopenharmony_ci        uint64_t toRead = count;
708bf80f4bSopenharmony_ci        if ((index_ + toRead) > size_) {
718bf80f4bSopenharmony_ci            toRead = size_ - index_;
728bf80f4bSopenharmony_ci        }
738bf80f4bSopenharmony_ci
748bf80f4bSopenharmony_ci        if (toRead > 0) {
758bf80f4bSopenharmony_ci            if (toRead <= SIZE_MAX) {
768bf80f4bSopenharmony_ci                if (CloneData(buffer, static_cast<size_t>(count), data_ + index_, static_cast<size_t>(toRead))) {
778bf80f4bSopenharmony_ci                    index_ += toRead;
788bf80f4bSopenharmony_ci                }
798bf80f4bSopenharmony_ci            } else {
808bf80f4bSopenharmony_ci                CORE_ASSERT_MSG(false, "Unable to read chunks bigger than (SIZE_MAX) bytes.");
818bf80f4bSopenharmony_ci                toRead = 0;
828bf80f4bSopenharmony_ci            }
838bf80f4bSopenharmony_ci        }
848bf80f4bSopenharmony_ci
858bf80f4bSopenharmony_ci        return toRead;
868bf80f4bSopenharmony_ci    }
878bf80f4bSopenharmony_ci
888bf80f4bSopenharmony_ci    uint64_t Write(const void* /* buffer */, uint64_t /* count */) override
898bf80f4bSopenharmony_ci    {
908bf80f4bSopenharmony_ci        return 0;
918bf80f4bSopenharmony_ci    }
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_ci    uint64_t GetLength() const override
948bf80f4bSopenharmony_ci    {
958bf80f4bSopenharmony_ci        return size_;
968bf80f4bSopenharmony_ci    }
978bf80f4bSopenharmony_ci
988bf80f4bSopenharmony_ci    bool Seek(uint64_t offset) override
998bf80f4bSopenharmony_ci    {
1008bf80f4bSopenharmony_ci        if (offset < size_) {
1018bf80f4bSopenharmony_ci            index_ = offset;
1028bf80f4bSopenharmony_ci            return true;
1038bf80f4bSopenharmony_ci        }
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_ci        return false;
1068bf80f4bSopenharmony_ci    }
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci    uint64_t GetPosition() const override
1098bf80f4bSopenharmony_ci    {
1108bf80f4bSopenharmony_ci        return index_;
1118bf80f4bSopenharmony_ci    }
1128bf80f4bSopenharmony_ci
1138bf80f4bSopenharmony_ciprotected:
1148bf80f4bSopenharmony_ci    void Destroy() override
1158bf80f4bSopenharmony_ci    {
1168bf80f4bSopenharmony_ci        delete this;
1178bf80f4bSopenharmony_ci    }
1188bf80f4bSopenharmony_ci
1198bf80f4bSopenharmony_ciprivate:
1208bf80f4bSopenharmony_ci    uint64_t index_ { 0 };
1218bf80f4bSopenharmony_ci    const uint8_t* const data_;
1228bf80f4bSopenharmony_ci    const size_t size_;
1238bf80f4bSopenharmony_ci};
1248bf80f4bSopenharmony_ci
1258bf80f4bSopenharmony_ciclass ROFSMemoryDirectory final : public IDirectory {
1268bf80f4bSopenharmony_cipublic:
1278bf80f4bSopenharmony_ci    ~ROFSMemoryDirectory() override = default;
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci    explicit ROFSMemoryDirectory(const vector<IDirectory::Entry>& contents) : contents_(contents) {}
1308bf80f4bSopenharmony_ci
1318bf80f4bSopenharmony_ci    ROFSMemoryDirectory(const ROFSMemoryDirectory&) = delete;
1328bf80f4bSopenharmony_ci    ROFSMemoryDirectory(ROFSMemoryDirectory&&) = delete;
1338bf80f4bSopenharmony_ci    ROFSMemoryDirectory& operator=(const ROFSMemoryDirectory&) = delete;
1348bf80f4bSopenharmony_ci    ROFSMemoryDirectory& operator=(ROFSMemoryDirectory&&) = delete;
1358bf80f4bSopenharmony_ci
1368bf80f4bSopenharmony_ci    void Close() override {}
1378bf80f4bSopenharmony_ci
1388bf80f4bSopenharmony_ci    vector<Entry> GetEntries() const override
1398bf80f4bSopenharmony_ci    {
1408bf80f4bSopenharmony_ci        return contents_;
1418bf80f4bSopenharmony_ci    }
1428bf80f4bSopenharmony_ci
1438bf80f4bSopenharmony_ciprotected:
1448bf80f4bSopenharmony_ci    void Destroy() override
1458bf80f4bSopenharmony_ci    {
1468bf80f4bSopenharmony_ci        delete this;
1478bf80f4bSopenharmony_ci    }
1488bf80f4bSopenharmony_ci
1498bf80f4bSopenharmony_ciprivate:
1508bf80f4bSopenharmony_ci    const vector<IDirectory::Entry>& contents_;
1518bf80f4bSopenharmony_ci};
1528bf80f4bSopenharmony_ci
1538bf80f4bSopenharmony_cistring_view Trim(string_view path)
1548bf80f4bSopenharmony_ci{
1558bf80f4bSopenharmony_ci    // remove leading and trailing slash..
1568bf80f4bSopenharmony_ci    if (!path.empty()) {
1578bf80f4bSopenharmony_ci        if (path.back() == '/') {
1588bf80f4bSopenharmony_ci            path.remove_suffix(1U);
1598bf80f4bSopenharmony_ci        }
1608bf80f4bSopenharmony_ci    }
1618bf80f4bSopenharmony_ci    if (!path.empty()) {
1628bf80f4bSopenharmony_ci        if (path.front() == '/') {
1638bf80f4bSopenharmony_ci            path.remove_prefix(1);
1648bf80f4bSopenharmony_ci        }
1658bf80f4bSopenharmony_ci    }
1668bf80f4bSopenharmony_ci    return path;
1678bf80f4bSopenharmony_ci}
1688bf80f4bSopenharmony_ci} // namespace
1698bf80f4bSopenharmony_ci
1708bf80f4bSopenharmony_ciRoFileSystem::RoFileSystem(const void* const blob, size_t blobSize)
1718bf80f4bSopenharmony_ci{
1728bf80f4bSopenharmony_ci    for (size_t i = 0; i < blobSize; i++) {
1738bf80f4bSopenharmony_ci        IDirectory::Entry entry;
1748bf80f4bSopenharmony_ci        const auto& romEntry = (reinterpret_cast<const FsEntry*>(blob))[i];
1758bf80f4bSopenharmony_ci        if (romEntry.fname[0] == 0) {
1768bf80f4bSopenharmony_ci            break;
1778bf80f4bSopenharmony_ci        }
1788bf80f4bSopenharmony_ci        const string_view tmp = romEntry.fname;
1798bf80f4bSopenharmony_ci        size_t t = 0;
1808bf80f4bSopenharmony_ci        string path;
1818bf80f4bSopenharmony_ci        for (;;) {
1828bf80f4bSopenharmony_ci            const size_t t2 = tmp.find_first_of('/', t);
1838bf80f4bSopenharmony_ci            if (t2 == string::npos) {
1848bf80f4bSopenharmony_ci                break;
1858bf80f4bSopenharmony_ci            }
1868bf80f4bSopenharmony_ci            t = t2;
1878bf80f4bSopenharmony_ci            const auto pathLength = path.length();
1888bf80f4bSopenharmony_ci            entry.name = tmp.substr(pathLength, t - pathLength);
1898bf80f4bSopenharmony_ci            path.reserve(pathLength + entry.name.length() + 1);
1908bf80f4bSopenharmony_ci            path += entry.name;
1918bf80f4bSopenharmony_ci            path += '/';
1928bf80f4bSopenharmony_ci            if (directories_.find(path) == directories_.end()) {
1938bf80f4bSopenharmony_ci                // new directory seen
1948bf80f4bSopenharmony_ci                entry.type = IDirectory::Entry::DIRECTORY;
1958bf80f4bSopenharmony_ci                const auto& parentDir = Trim(path.substr(0, pathLength));
1968bf80f4bSopenharmony_ci                if (const auto pos = directories_.find(parentDir); pos != directories_.cend()) {
1978bf80f4bSopenharmony_ci                    // add each subdirectory only once
1988bf80f4bSopenharmony_ci                    if (std::none_of(
1998bf80f4bSopenharmony_ci                        pos->second.cbegin(), pos->second.cend(), [&entry](const IDirectory::Entry& child) {
2008bf80f4bSopenharmony_ci                            return child.type == entry.type && child.name == entry.name;
2018bf80f4bSopenharmony_ci                        })) {
2028bf80f4bSopenharmony_ci                        pos->second.push_back(move(entry));
2038bf80f4bSopenharmony_ci                    }
2048bf80f4bSopenharmony_ci                } else {
2058bf80f4bSopenharmony_ci                    directories_[string(parentDir)].push_back(move(entry));
2068bf80f4bSopenharmony_ci                }
2078bf80f4bSopenharmony_ci                directories_[path.substr(0, path.length() - 1)].reserve(1);
2088bf80f4bSopenharmony_ci            }
2098bf80f4bSopenharmony_ci            t++;
2108bf80f4bSopenharmony_ci        }
2118bf80f4bSopenharmony_ci        // add the file entry..
2128bf80f4bSopenharmony_ci        entry.name = tmp.substr(t);
2138bf80f4bSopenharmony_ci        entry.type = IDirectory::Entry::FILE;
2148bf80f4bSopenharmony_ci        const auto pathLength = path.length();
2158bf80f4bSopenharmony_ci        path.reserve(pathLength + entry.name.length());
2168bf80f4bSopenharmony_ci        path += entry.name;
2178bf80f4bSopenharmony_ci        directories_[Trim(path.substr(0, pathLength))].push_back(move(entry));
2188bf80f4bSopenharmony_ci        auto* data = reinterpret_cast<const uint8_t*>(blob) + romEntry.offset;
2198bf80f4bSopenharmony_ci        files_[move(path)] = array_view(data, static_cast<size_t>(romEntry.size));
2208bf80f4bSopenharmony_ci    }
2218bf80f4bSopenharmony_ci}
2228bf80f4bSopenharmony_ci
2238bf80f4bSopenharmony_ciIDirectory::Entry RoFileSystem::GetEntry(const string_view uri)
2248bf80f4bSopenharmony_ci{
2258bf80f4bSopenharmony_ci    const string_view t = Trim(uri);
2268bf80f4bSopenharmony_ci    // check if it's a file first...
2278bf80f4bSopenharmony_ci    const auto it = files_.find(t);
2288bf80f4bSopenharmony_ci    if (it != files_.end()) {
2298bf80f4bSopenharmony_ci        return { IDirectory::Entry::FILE, string(uri), 0 };
2308bf80f4bSopenharmony_ci    }
2318bf80f4bSopenharmony_ci    // is it a directory then
2328bf80f4bSopenharmony_ci    const auto it2 = directories_.find(t);
2338bf80f4bSopenharmony_ci    if (it2 != directories_.end()) {
2348bf80f4bSopenharmony_ci        return { IDirectory::Entry::DIRECTORY, string(uri), 0 };
2358bf80f4bSopenharmony_ci    }
2368bf80f4bSopenharmony_ci    // nope. does not exist.
2378bf80f4bSopenharmony_ci    return {};
2388bf80f4bSopenharmony_ci}
2398bf80f4bSopenharmony_ci
2408bf80f4bSopenharmony_ciIFile::Ptr RoFileSystem::OpenFile(const string_view path)
2418bf80f4bSopenharmony_ci{
2428bf80f4bSopenharmony_ci    auto it = files_.find(Trim(path));
2438bf80f4bSopenharmony_ci    if (it != files_.end()) {
2448bf80f4bSopenharmony_ci        return IFile::Ptr { new ROFSMemoryFile(it->second.data(), it->second.size()) };
2458bf80f4bSopenharmony_ci    }
2468bf80f4bSopenharmony_ci    return IFile::Ptr();
2478bf80f4bSopenharmony_ci}
2488bf80f4bSopenharmony_ci
2498bf80f4bSopenharmony_ciIFile::Ptr RoFileSystem::CreateFile(const string_view /* path */)
2508bf80f4bSopenharmony_ci{
2518bf80f4bSopenharmony_ci    return IFile::Ptr();
2528bf80f4bSopenharmony_ci}
2538bf80f4bSopenharmony_ci
2548bf80f4bSopenharmony_cibool RoFileSystem::DeleteFile(const string_view /* path */)
2558bf80f4bSopenharmony_ci{
2568bf80f4bSopenharmony_ci    return false;
2578bf80f4bSopenharmony_ci}
2588bf80f4bSopenharmony_ci
2598bf80f4bSopenharmony_ciIDirectory::Ptr RoFileSystem::OpenDirectory(const string_view path)
2608bf80f4bSopenharmony_ci{
2618bf80f4bSopenharmony_ci    const string_view t = Trim(path);
2628bf80f4bSopenharmony_ci    auto it = directories_.find(t);
2638bf80f4bSopenharmony_ci    if (it != directories_.end()) {
2648bf80f4bSopenharmony_ci        return IDirectory::Ptr { new ROFSMemoryDirectory(it->second) };
2658bf80f4bSopenharmony_ci    }
2668bf80f4bSopenharmony_ci    return IDirectory::Ptr();
2678bf80f4bSopenharmony_ci}
2688bf80f4bSopenharmony_ci
2698bf80f4bSopenharmony_ciIDirectory::Ptr RoFileSystem::CreateDirectory(const string_view /* path */)
2708bf80f4bSopenharmony_ci{
2718bf80f4bSopenharmony_ci    return IDirectory::Ptr();
2728bf80f4bSopenharmony_ci}
2738bf80f4bSopenharmony_ci
2748bf80f4bSopenharmony_cibool RoFileSystem::DeleteDirectory(const string_view /* path */)
2758bf80f4bSopenharmony_ci{
2768bf80f4bSopenharmony_ci    return false;
2778bf80f4bSopenharmony_ci}
2788bf80f4bSopenharmony_ci
2798bf80f4bSopenharmony_cibool RoFileSystem::Rename(const string_view /* fromPath */, const string_view /* toPath */)
2808bf80f4bSopenharmony_ci{
2818bf80f4bSopenharmony_ci    return false;
2828bf80f4bSopenharmony_ci}
2838bf80f4bSopenharmony_ci
2848bf80f4bSopenharmony_civector<string> RoFileSystem::GetUriPaths(const string_view) const
2858bf80f4bSopenharmony_ci{
2868bf80f4bSopenharmony_ci    return {};
2878bf80f4bSopenharmony_ci}
2888bf80f4bSopenharmony_ciCORE_END_NAMESPACE()
289