bump product version to 5.0.4.1
[LibreOffice.git] / unoidl / source / sourcetreeprovider.cxx
blobe9d00940bb69e080b5ec3ed17313a2b5af21a66f
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"
12 #include <map>
13 #include <vector>
14 #include <cstring>
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-parser-requires.hxx"
25 #include "sourceprovider-parser.hxx"
26 #include "sourceprovider-scanner.hxx"
27 #include "sourcetreeprovider.hxx"
29 #if defined MACOSX
30 #include <dirent.h>
31 #include "osl/thread.h"
32 #endif
34 namespace unoidl { namespace detail {
36 namespace {
38 //TODO: Bad hack to work around osl::FileStatus::getFileName not determining the
39 // original spelling of a file name (not even with
40 // osl_FileStatus_Mask_Validate):
41 OUString getFileName(OUString const & uri, osl::FileStatus & status) {
42 #if defined MACOSX
43 sal_Int32 i = uri.lastIndexOf('/') + 1;
44 OUString path;
45 if (osl::FileBase::getSystemPathFromFileURL(uri.copy(0, i), path)
46 != osl::FileBase::E_None)
48 SAL_WARN(
49 "unoidl",
50 "cannot getSystemPathFromFileURL(" << uri.copy(0, i) << ")");
51 return status.getFileName();
53 OString dir(OUStringToOString(path, osl_getThreadTextEncoding()));
54 OString name(OUStringToOString(uri.copy(i), osl_getThreadTextEncoding()));
55 DIR * d = opendir(dir.getStr());
56 if (d == 0) {
57 SAL_WARN("unoidl", "cannot opendir(" << dir << ")");
58 return status.getFileName();
60 for (;;) {
61 dirent ent;
62 dirent * p;
63 int e = readdir_r(d, &ent, &p);
64 if (e != 0) {
65 SAL_WARN("unoidl", "cannot readdir_r");
66 closedir(d);
67 return status.getFileName();
69 if (p == 0) {
70 SAL_WARN(
71 "unoidl", "cannot find " << name << " via readdir of " << dir);
72 closedir(d);
73 return status.getFileName();
75 if (name.equalsIgnoreAsciiCase(p->d_name)) {
76 closedir(d);
77 return OUString(
78 p->d_name, std::strlen(p->d_name), osl_getThreadTextEncoding());
81 #else
82 (void) uri;
83 return status.getFileName();
84 #endif
87 bool exists(OUString const & uri, bool directory) {
88 osl::DirectoryItem item;
89 osl::FileStatus status(
90 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName);
91 return osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None
92 && item.getFileStatus(status) == osl::FileBase::E_None
93 && (status.getFileType() == osl::FileStatus::Directory) == directory
94 && getFileName(uri, status) == uri.copy(uri.lastIndexOf('/') + 1);
97 class Cursor: public MapCursor {
98 public:
99 Cursor() {}
101 private:
102 virtual ~Cursor() throw () {}
104 virtual rtl::Reference<Entity> getNext(OUString *) SAL_OVERRIDE
105 { return rtl::Reference<Entity>(); } //TODO
108 class SourceModuleEntity: public ModuleEntity {
109 public:
110 SourceModuleEntity() {}
112 private:
113 virtual ~SourceModuleEntity() throw () {}
115 virtual std::vector<OUString> getMemberNames() const SAL_OVERRIDE
116 { return std::vector<OUString>(); } //TODO
118 virtual rtl::Reference< MapCursor > createCursor() const SAL_OVERRIDE
119 { return new Cursor; }
124 SourceTreeProvider::SourceTreeProvider(Manager & manager, OUString const & uri):
125 manager_(manager), uri_(uri.endsWith("/") ? uri : uri + "/")
128 rtl::Reference<MapCursor> SourceTreeProvider::createRootCursor() const {
129 return new Cursor;
132 rtl::Reference<Entity> SourceTreeProvider::findEntity(OUString const & name)
133 const
135 std::map< OUString, rtl::Reference<Entity> >::iterator ci(
136 cache_.find(name));
137 if (ci != cache_.end()) {
138 return ci->second;
140 // Match name against
141 // name ::= identifier ("." identifier)*
142 // identifier ::= upper-blocks | lower-block
143 // upper-blocks ::= upper ("_"? alnum)*
144 // lower-block :== lower alnum*
145 // alnum ::= digit | upper | lower
146 // digit ::= "0"--"9"
147 // upper ::= "A"--"Z"
148 // lower ::= "a"--"z"
149 OUStringBuffer buf(name);
150 sal_Int32 start = 0;
151 sal_Int32 i = 0;
152 for (; i != name.getLength(); ++i) {
153 sal_Unicode c = name[i];
154 if (c == '.') {
155 assert(i == start || i != 0);
156 if (i == start || name[i - 1] == '_') {
157 throw FileFormatException( //TODO
158 "", "Illegal UNOIDL identifier \"" + name + "\"");
160 buf[i] = '/';
161 start = i + 1;
162 } else if (c == '_') {
163 assert(i == start || i != 0);
164 if (i == start || name[i - 1] == '_'
165 || !rtl::isAsciiUpperCase(name[start]))
167 throw FileFormatException( //TODO
168 "", "Illegal UNOIDL identifier \"" + name + "\"");
170 } else if (rtl::isAsciiDigit(c)) {
171 if (i == start) {
172 throw FileFormatException( //TODO
173 "", "Illegal UNOIDL identifier \"" + name + "\"");
175 } else if (!rtl::isAsciiAlpha(c)) {
176 throw FileFormatException( //TODO
177 "", "Illegal UNOIDL identifier \"" + name + "\"");
180 if (i == start) {
181 throw FileFormatException( //TODO
182 "", "Illegal UNOIDL identifier \"" + name + "\"");
184 OUString uri(uri_ + buf.makeStringAndClear());
185 rtl::Reference<Entity> ent;
186 // Prevent conflicts between foo/ and Foo.idl on case-preserving file
187 // systems:
188 if (exists(uri, true) && !exists(uri + ".idl", false)) {
189 ent = new SourceModuleEntity;
190 } else {
191 uri += ".idl";
192 SourceProviderScannerData data(&manager_);
193 if (parse(uri, &data)) {
194 std::map<OUString, SourceProviderEntity>::const_iterator j(
195 data.entities.find(name));
196 if (j != data.entities.end()) {
197 ent = j->second.entity;
199 SAL_WARN_IF(
200 !ent.is(), "unoidl",
201 "<" << uri << "> does not define entity " << name);
204 cache_.insert(
205 std::map< OUString, rtl::Reference<Entity> >::value_type(name, ent));
206 return ent;
209 SourceTreeProvider::~SourceTreeProvider() throw () {}
213 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */