diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2021-09-14 17:11:12 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2021-09-21 07:49:27 +0200 |
commit | 7b10f119040144ff7db1da4c0a2bbdd488dcdf0f (patch) | |
tree | f81b575f2f752f022a1fac714cb97672deb4bc5d /unoidl | |
parent | 5c98fcffb23a9da8459e35bdd9946422fec8a320 (diff) |
Implement the SourceTreeProvider Cursor
Change-Id: Ibf54bd1e852ea23fb37c7222625895d240452424
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122361
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'unoidl')
-rw-r--r-- | unoidl/source/sourcetreeprovider.cxx | 118 |
1 files changed, 111 insertions, 7 deletions
diff --git a/unoidl/source/sourcetreeprovider.cxx b/unoidl/source/sourcetreeprovider.cxx index 9531d057c979..404938c376cc 100644 --- a/unoidl/source/sourcetreeprovider.cxx +++ b/unoidl/source/sourcetreeprovider.cxx @@ -94,18 +94,24 @@ bool exists(OUString const & uri, bool directory) { class Cursor: public MapCursor { public: - Cursor() {} + Cursor(Manager& manager, OUString const & uri): manager_(manager), directory_(uri) { + auto const rc = directory_.open(); + SAL_WARN_IF( + rc != osl::FileBase::E_None, "unoidl", "open(" << uri << ") failed with " << +rc); + } private: virtual ~Cursor() noexcept override {} - virtual rtl::Reference<Entity> getNext(OUString *) override - { return rtl::Reference<Entity>(); } //TODO + virtual rtl::Reference<Entity> getNext(OUString *) override; + + Manager& manager_; + osl::Directory directory_; }; class SourceModuleEntity: public ModuleEntity { public: - SourceModuleEntity() {} + SourceModuleEntity(Manager& manager, OUString const & uri): manager_(manager), uri_(uri) {} private: virtual ~SourceModuleEntity() noexcept override {} @@ -114,9 +120,107 @@ private: { return std::vector<OUString>(); } //TODO virtual rtl::Reference< MapCursor > createCursor() const override - { return new Cursor; } + { return new Cursor(manager_, uri_); } + + Manager& manager_; + OUString uri_; }; +bool isValidFileName(OUString const & name, bool directory) { + for (sal_Int32 i = 0;; ++i) { + if (i == name.getLength()) { + if (i == 0) { + return false; + } + return directory; + } + auto const c = name[i]; + if (c == '.') { + if (i == 0 || name[i - 1] == '_') { + return false; + } + return !directory && name.subView(i + 1) == u"idl"; + } else if (c == '_') { + //TODO: Ignore case of name[0] only for case-insensitive file systems: + if (i == 0 || name[i - 1] == '_') { + return false; + } + } else if (rtl::isAsciiDigit(c)) { + if (i == 0) { + return false; + } + } else if (!rtl::isAsciiAlpha(c)) { + return false; + } + } +} + +} + +rtl::Reference<Entity> Cursor::getNext(OUString * name) { + assert(name != nullptr); + for (;;) { + osl::DirectoryItem i; + auto rc = directory_.getNextItem(i); + switch (rc) { + case osl::FileBase::E_None: + { + osl::FileStatus stat( + osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName | + osl_FileStatus_Mask_FileURL); + rc = i.getFileStatus(stat); + if (rc != osl::FileBase::E_None) { + SAL_WARN( + "unoidl", + "getFileSatus in <" << directory_.getURL() << "> failed with " << +rc); + continue; + } + auto const dir = stat.getFileType() == osl::FileStatus::Directory; + if (!isValidFileName(stat.getFileName(), dir)) { + continue; + } + if (dir) { + //TODO: Using osl::FileStatus::getFileName can likely cause issues on case- + // insensitive/preserving file systems, see the free getFileName function above + // (which likely goes unnoticed if module identifiers follow the convention of + // being all-lowercase): + *name = stat.getFileName(); + return new SourceModuleEntity(manager_, stat.getFileURL()); + } else { + SourceProviderScannerData data(&manager_); + if (!parse(stat.getFileURL(), &data)) { + SAL_WARN("unoidl", "cannot parse <" << stat.getFileURL() << ">"); + continue; + } + auto ent = data.entities.end(); + for (auto j = data.entities.begin(); j != data.entities.end(); ++j) { + if (j->second.kind == SourceProviderEntity::KIND_EXTERNAL + || j->second.kind == SourceProviderEntity::KIND_MODULE) + { + continue; + } + if (ent != data.entities.end()) { + throw FileFormatException( + stat.getFileURL(), "source file defines more than one entity"); + } + ent = j; + } + if (ent == data.entities.end()) { + throw FileFormatException( + stat.getFileURL(), "source file defines no entity"); + } + //TODO: Check that the entity's name matches the suffix of stat.getFileURL(): + *name = ent->first.copy(ent->first.lastIndexOf('.') + 1); + return ent->second.entity; + } + } + default: + SAL_WARN( "unoidl", "getNext from <" << directory_.getURL() << "> failed with " << +rc); + [[fallthrough]]; + case osl::FileBase::E_NOENT: + return {}; + } + } } SourceTreeProvider::SourceTreeProvider(Manager & manager, OUString const & uri): @@ -124,7 +228,7 @@ SourceTreeProvider::SourceTreeProvider(Manager & manager, OUString const & uri): {} rtl::Reference<MapCursor> SourceTreeProvider::createRootCursor() const { - return new Cursor; + return new Cursor(manager_, uri_); } rtl::Reference<Entity> SourceTreeProvider::findEntity(OUString const & name) @@ -184,7 +288,7 @@ rtl::Reference<Entity> SourceTreeProvider::findEntity(OUString const & name) // Prevent conflicts between foo/ and Foo.idl on case-preserving file // systems: if (exists(uri, true) && !exists(uri + ".idl", false)) { - ent = new SourceModuleEntity; + ent = new SourceModuleEntity(manager_, uri); } else { uri += ".idl"; SourceProviderScannerData data(&manager_); |