Line data Source code
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 "sal/config.h"
11 :
12 : #include <map>
13 : #include <vector>
14 : #include <cstring>
15 :
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"
23 :
24 : #include "sourceprovider-parser-requires.hxx"
25 : #include "sourceprovider-parser.hxx"
26 : #include "sourceprovider-scanner.hxx"
27 : #include "sourcetreeprovider.hxx"
28 :
29 : #if defined MACOSX
30 : #include <dirent.h>
31 : #include "osl/thread.h"
32 : #endif
33 :
34 : namespace unoidl { namespace detail {
35 :
36 : namespace {
37 :
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 139 : 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)
47 : {
48 : SAL_WARN(
49 : "unoidl",
50 : "cannot getSystemPathFromFileURL(" << uri.copy(0, i) << ")");
51 : return status.getFileName();
52 : }
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();
59 : }
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();
68 : }
69 : if (p == 0) {
70 : SAL_WARN(
71 : "unoidl", "cannot find " << name << " via readdir of " << dir);
72 : closedir(d);
73 : return status.getFileName();
74 : }
75 : if (name.equalsIgnoreAsciiCase(p->d_name)) {
76 : closedir(d);
77 : return OUString(
78 : p->d_name, std::strlen(p->d_name), osl_getThreadTextEncoding());
79 : }
80 : }
81 : #else
82 : (void) uri;
83 139 : return status.getFileName();
84 : #endif
85 : }
86 :
87 12443 : bool exists(OUString const & uri, bool directory) {
88 12443 : osl::DirectoryItem item;
89 : osl::FileStatus status(
90 24886 : osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName);
91 12443 : return osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None
92 139 : && item.getFileStatus(status) == osl::FileBase::E_None
93 139 : && (status.getFileType() == osl::FileStatus::Directory) == directory
94 37468 : && getFileName(uri, status) == uri.copy(uri.lastIndexOf('/') + 1);
95 : }
96 :
97 : class Cursor: public MapCursor {
98 : public:
99 0 : Cursor() {}
100 :
101 : private:
102 0 : virtual ~Cursor() throw () {}
103 :
104 0 : virtual rtl::Reference<Entity> getNext(OUString *) SAL_OVERRIDE
105 0 : { return rtl::Reference<Entity>(); } //TODO
106 : };
107 :
108 : class SourceModuleEntity: public ModuleEntity {
109 : public:
110 139 : SourceModuleEntity() {}
111 :
112 : private:
113 278 : virtual ~SourceModuleEntity() throw () {}
114 :
115 0 : virtual std::vector<OUString> getMemberNames() const SAL_OVERRIDE
116 0 : { return std::vector<OUString>(); } //TODO
117 :
118 0 : virtual rtl::Reference< MapCursor > createCursor() const SAL_OVERRIDE
119 0 : { return new Cursor; }
120 : };
121 :
122 : }
123 :
124 334 : SourceTreeProvider::SourceTreeProvider(Manager & manager, OUString const & uri):
125 334 : manager_(manager), uri_(uri.endsWith("/") ? uri : uri + "/")
126 334 : {}
127 :
128 0 : rtl::Reference<MapCursor> SourceTreeProvider::createRootCursor() const {
129 0 : return new Cursor;
130 : }
131 :
132 47166 : rtl::Reference<Entity> SourceTreeProvider::findEntity(OUString const & name)
133 : const
134 : {
135 : std::map< OUString, rtl::Reference<Entity> >::iterator ci(
136 47166 : cache_.find(name));
137 47166 : if (ci != cache_.end()) {
138 34862 : return ci->second;
139 : }
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 12304 : OUStringBuffer buf(name);
150 12304 : sal_Int32 start = 0;
151 12304 : sal_Int32 i = 0;
152 529696 : for (; i != name.getLength(); ++i) {
153 517392 : sal_Unicode c = name[i];
154 517392 : if (c == '.') {
155 : assert(i == start || i != 0);
156 68204 : if (i == start || name[i - 1] == '_') {
157 : throw FileFormatException( //TODO
158 0 : "", "Illegal UNOIDL identifier \"" + name + "\"");
159 : }
160 68204 : buf[i] = '/';
161 68204 : start = i + 1;
162 449188 : } else if (c == '_') {
163 : assert(i == start || i != 0);
164 20 : if (i == start || name[i - 1] == '_'
165 20 : || !rtl::isAsciiUpperCase(name[start]))
166 : {
167 : throw FileFormatException( //TODO
168 0 : "", "Illegal UNOIDL identifier \"" + name + "\"");
169 : }
170 449178 : } else if (rtl::isAsciiDigit(c)) {
171 1094 : if (i == start) {
172 : throw FileFormatException( //TODO
173 0 : "", "Illegal UNOIDL identifier \"" + name + "\"");
174 : }
175 448084 : } else if (!rtl::isAsciiAlpha(c)) {
176 : throw FileFormatException( //TODO
177 0 : "", "Illegal UNOIDL identifier \"" + name + "\"");
178 : }
179 : }
180 12304 : if (i == start) {
181 : throw FileFormatException( //TODO
182 0 : "", "Illegal UNOIDL identifier \"" + name + "\"");
183 : }
184 24608 : OUString uri(uri_ + buf.makeStringAndClear());
185 24608 : rtl::Reference<Entity> ent;
186 : // Prevent conflicts between foo/ and Foo.idl on case-preserving file
187 : // systems:
188 12304 : if (exists(uri, true) && !exists(uri + ".idl", false)) {
189 139 : ent = new SourceModuleEntity;
190 : } else {
191 12165 : uri += ".idl";
192 12165 : SourceProviderScannerData data(&manager_);
193 12165 : if (parse(uri, &data)) {
194 : std::map<OUString, SourceProviderEntity>::const_iterator j(
195 5470 : data.entities.find(name));
196 5470 : if (j != data.entities.end()) {
197 5470 : ent = j->second.entity;
198 : }
199 : SAL_WARN_IF(
200 : !ent.is(), "unoidl",
201 : "<" << uri << "> does not define entity " << name);
202 12165 : }
203 : }
204 : cache_.insert(
205 12304 : std::map< OUString, rtl::Reference<Entity> >::value_type(name, ent));
206 24608 : return ent;
207 : }
208 :
209 668 : SourceTreeProvider::~SourceTreeProvider() throw () {}
210 :
211 : } }
212 :
213 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|