bump product version to 6.4.0.3
[LibreOffice.git] / unoidl / source / sourcetreeprovider.cxx
blob0d88c8e0565a13c26863edf6f492d060d870cdc4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
11 #include <sal/log.hxx>
13 #include <map>
14 #include <vector>
16 #include <osl/file.h>
17 #include <osl/file.hxx>
18 #include <rtl/character.hxx>
19 #include <rtl/ref.hxx>
20 #include <rtl/ustrbuf.hxx>
21 #include <rtl/ustring.hxx>
22 #include <unoidl/unoidl.hxx>
24 #include "sourceprovider-scanner.hxx"
25 #include "sourcetreeprovider.hxx"
27 #if defined MACOSX
28 #include <dirent.h>
29 #include <osl/thread.h>
30 #endif
32 namespace unoidl { namespace detail {
34 namespace {
36 //TODO: Bad hack to work around osl::FileStatus::getFileName not determining the
37 // original spelling of a file name (not even with
38 // osl_FileStatus_Mask_Validate):
39 OUString getFileName(OUString const & uri, osl::FileStatus const & status) {
40 #if defined MACOSX
41 sal_Int32 i = uri.lastIndexOf('/') + 1;
42 OUString path;
43 if (osl::FileBase::getSystemPathFromFileURL(uri.copy(0, i), path)
44 != osl::FileBase::E_None)
46 SAL_WARN(
47 "unoidl",
48 "cannot getSystemPathFromFileURL(" << uri.copy(0, i) << ")");
49 return status.getFileName();
51 OString dir(OUStringToOString(path, osl_getThreadTextEncoding()));
52 OString name(OUStringToOString(uri.copy(i), osl_getThreadTextEncoding()));
53 DIR * d = opendir(dir.getStr());
54 if (d == nullptr) {
55 SAL_WARN("unoidl", "cannot opendir(" << dir << ")");
56 return status.getFileName();
58 for (;;) {
59 dirent ent;
60 dirent * p;
61 int e = readdir_r(d, &ent, &p);
62 if (e != 0) {
63 SAL_WARN("unoidl", "cannot readdir_r");
64 closedir(d);
65 return status.getFileName();
67 if (p == nullptr) {
68 SAL_WARN(
69 "unoidl", "cannot find " << name << " via readdir of " << dir);
70 closedir(d);
71 return status.getFileName();
73 if (name.equalsIgnoreAsciiCase(p->d_name)) {
74 closedir(d);
75 return OUString(
76 p->d_name, std::strlen(p->d_name), osl_getThreadTextEncoding());
79 #else
80 (void) uri;
81 return status.getFileName();
82 #endif
85 bool exists(OUString const & uri, bool directory) {
86 osl::DirectoryItem item;
87 osl::FileStatus status(
88 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName);
89 return osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None
90 && item.getFileStatus(status) == osl::FileBase::E_None
91 && (status.getFileType() == osl::FileStatus::Directory) == directory
92 && getFileName(uri, status) == uri.copy(uri.lastIndexOf('/') + 1);
95 class Cursor: public MapCursor {
96 public:
97 Cursor() {}
99 private:
100 virtual ~Cursor() throw () override {}
102 virtual rtl::Reference<Entity> getNext(OUString *) override
103 { return rtl::Reference<Entity>(); } //TODO
106 class SourceModuleEntity: public ModuleEntity {
107 public:
108 SourceModuleEntity() {}
110 private:
111 virtual ~SourceModuleEntity() throw () override {}
113 virtual std::vector<OUString> getMemberNames() const override
114 { return std::vector<OUString>(); } //TODO
116 virtual rtl::Reference< MapCursor > createCursor() const override
117 { return new Cursor; }
122 SourceTreeProvider::SourceTreeProvider(Manager & manager, OUString const & uri):
123 manager_(manager), uri_(uri.endsWith("/") ? uri : uri + "/")
126 rtl::Reference<MapCursor> SourceTreeProvider::createRootCursor() const {
127 return new Cursor;
130 rtl::Reference<Entity> SourceTreeProvider::findEntity(OUString const & name)
131 const
133 std::map< OUString, rtl::Reference<Entity> >::iterator ci(
134 cache_.find(name));
135 if (ci != cache_.end()) {
136 return ci->second;
138 // Match name against
139 // name ::= identifier ("." identifier)*
140 // identifier ::= upper-blocks | lower-block
141 // upper-blocks ::= upper ("_"? alnum)*
142 // lower-block :== lower alnum*
143 // alnum ::= digit | upper | lower
144 // digit ::= "0"--"9"
145 // upper ::= "A"--"Z"
146 // lower ::= "a"--"z"
147 OUStringBuffer buf(name);
148 sal_Int32 start = 0;
149 sal_Int32 i = 0;
150 for (; i != name.getLength(); ++i) {
151 sal_Unicode c = name[i];
152 if (c == '.') {
153 assert(i == start || i != 0);
154 if (i == start || name[i - 1] == '_') {
155 throw FileFormatException( //TODO
156 "", "Illegal UNOIDL identifier \"" + name + "\"");
158 buf[i] = '/';
159 start = i + 1;
160 } else if (c == '_') {
161 assert(i == start || i != 0);
162 if (i == start || name[i - 1] == '_'
163 || !rtl::isAsciiUpperCase(name[start]))
165 throw FileFormatException( //TODO
166 "", "Illegal UNOIDL identifier \"" + name + "\"");
168 } else if (rtl::isAsciiDigit(c)) {
169 if (i == start) {
170 throw FileFormatException( //TODO
171 "", "Illegal UNOIDL identifier \"" + name + "\"");
173 } else if (!rtl::isAsciiAlpha(c)) {
174 throw FileFormatException( //TODO
175 "", "Illegal UNOIDL identifier \"" + name + "\"");
178 if (i == start) {
179 throw FileFormatException( //TODO
180 "", "Illegal UNOIDL identifier \"" + name + "\"");
182 OUString uri(uri_ + buf.makeStringAndClear());
183 rtl::Reference<Entity> ent;
184 // Prevent conflicts between foo/ and Foo.idl on case-preserving file
185 // systems:
186 if (exists(uri, true) && !exists(uri + ".idl", false)) {
187 ent = new SourceModuleEntity;
188 } else {
189 uri += ".idl";
190 SourceProviderScannerData data(&manager_);
191 if (parse(uri, &data)) {
192 std::map<OUString, SourceProviderEntity>::const_iterator j(
193 data.entities.find(name));
194 if (j != data.entities.end()) {
195 ent = j->second.entity;
197 SAL_WARN_IF(
198 !ent.is(), "unoidl",
199 "<" << uri << "> does not define entity " << name);
202 cache_.emplace(name, ent);
203 return ent;
206 SourceTreeProvider::~SourceTreeProvider() throw () {}
210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */