1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Mike McCabe <mccabe@netscape.com>
24 : * John Bandhauer <jband@netscape.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* Implementation of xptiInterfaceInfoManager. */
41 :
42 : #include "xptiprivate.h"
43 : #include "nsDependentString.h"
44 : #include "nsString.h"
45 : #include "nsISupportsArray.h"
46 : #include "nsArrayEnumerator.h"
47 : #include "mozilla/FunctionTimer.h"
48 : #include "nsDirectoryService.h"
49 : #include "mozilla/FileUtils.h"
50 :
51 : using namespace mozilla;
52 :
53 678331 : NS_IMPL_THREADSAFE_ISUPPORTS2(xptiInterfaceInfoManager,
54 : nsIInterfaceInfoManager,
55 : nsIInterfaceInfoSuperManager)
56 :
57 : static xptiInterfaceInfoManager* gInterfaceInfoManager = nsnull;
58 : #ifdef DEBUG
59 : static int gCallCount = 0;
60 : #endif
61 :
62 : // static
63 : xptiInterfaceInfoManager*
64 1969627 : xptiInterfaceInfoManager::GetSingleton()
65 : {
66 1969627 : if (!gInterfaceInfoManager) {
67 : NS_TIME_FUNCTION;
68 :
69 1419 : gInterfaceInfoManager = new xptiInterfaceInfoManager();
70 1419 : NS_ADDREF(gInterfaceInfoManager);
71 : }
72 1969627 : return gInterfaceInfoManager;
73 : }
74 :
75 : void
76 1419 : xptiInterfaceInfoManager::FreeInterfaceInfoManager()
77 : {
78 1419 : NS_IF_RELEASE(gInterfaceInfoManager);
79 1419 : }
80 :
81 1419 : xptiInterfaceInfoManager::xptiInterfaceInfoManager()
82 : : mWorkingSet(),
83 : mResolveLock("xptiInterfaceInfoManager.mResolveLock"),
84 : mAdditionalManagersLock(
85 1419 : "xptiInterfaceInfoManager.mAdditionalManagersLock")
86 : {
87 1419 : }
88 :
89 2818 : xptiInterfaceInfoManager::~xptiInterfaceInfoManager()
90 : {
91 : // We only do this on shutdown of the service.
92 1409 : mWorkingSet.InvalidateInterfaceInfos();
93 :
94 1409 : gInterfaceInfoManager = nsnull;
95 : #ifdef DEBUG
96 1409 : gCallCount = 0;
97 : #endif
98 1409 : }
99 :
100 : void
101 218497 : xptiInterfaceInfoManager::RegisterBuffer(char *buf, PRUint32 length)
102 : {
103 218497 : XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length);
104 218497 : if (!state)
105 0 : return;
106 :
107 : XPTCursor cursor;
108 218497 : if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) {
109 0 : XPT_DestroyXDRState(state);
110 0 : return;
111 : }
112 :
113 218497 : XPTHeader *header = nsnull;
114 218497 : if (XPT_DoHeader(gXPTIStructArena, &cursor, &header)) {
115 218497 : RegisterXPTHeader(header);
116 : }
117 :
118 218497 : XPT_DestroyXDRState(state);
119 : }
120 :
121 : void
122 218497 : xptiInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader)
123 : {
124 218497 : if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
125 0 : NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt");
126 : LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION));
127 : }
128 :
129 218497 : xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader);
130 :
131 436994 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
132 3616498 : for(PRUint16 k = 0; k < aHeader->num_interfaces; k++)
133 3398001 : VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib);
134 218497 : }
135 :
136 : void
137 3398001 : xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
138 : PRUint16 idx,
139 : xptiTypelibGuts* typelib)
140 : {
141 3398001 : if (!iface->interface_descriptor)
142 1229947 : return;
143 :
144 : // The number of maximum methods is not arbitrary. It is the same value as
145 : // in xpcom/reflect/xptcall/public/genstubs.pl; do not change this value
146 : // without changing that one or you WILL see problems.
147 2169473 : if (iface->interface_descriptor->num_methods > 250 &&
148 1419 : !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) {
149 0 : NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load");
150 0 : fprintf(stderr, "ignoring too large interface: %s\n", iface->name);
151 0 : return;
152 : }
153 :
154 2168054 : mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn();
155 2168054 : xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid);
156 2168054 : if (entry) {
157 : // XXX validate this info to find possible inconsistencies
158 : LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name));
159 8336 : return;
160 : }
161 :
162 : // Build a new xptiInterfaceEntry object and hook it up.
163 :
164 : entry = xptiInterfaceEntry::Create(iface->name,
165 : iface->iid,
166 : iface->interface_descriptor,
167 2159718 : typelib);
168 2159718 : if (!entry)
169 0 : return;
170 :
171 : //XXX We should SetHeader too as part of the validation, no?
172 2159718 : entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
173 2159718 : entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags));
174 :
175 2159718 : mWorkingSet.mIIDTable.Put(entry->IID(), entry);
176 2159718 : mWorkingSet.mNameTable.Put(entry->GetTheName(), entry);
177 :
178 2159718 : typelib->SetEntryAt(idx, entry);
179 :
180 : LOG_AUTOREG((" added interface: %s\n", iface->name));
181 : }
182 :
183 : // this is a private helper
184 : static nsresult
185 654719 : EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
186 : {
187 : xptiInterfaceInfo* info;
188 : nsresult rv;
189 :
190 654719 : if (!entry) {
191 9033 : *_retval = nsnull;
192 9033 : return NS_ERROR_FAILURE;
193 : }
194 :
195 645686 : rv = entry->GetInterfaceInfo(&info);
196 645686 : if (NS_FAILED(rv))
197 0 : return rv;
198 :
199 : // Transfer the AddRef done by GetInterfaceInfo.
200 645686 : *_retval = static_cast<nsIInterfaceInfo*>(info);
201 645686 : return NS_OK;
202 : }
203 :
204 : xptiInterfaceEntry*
205 106804 : xptiInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid)
206 : {
207 213608 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
208 106804 : return mWorkingSet.mIIDTable.Get(*iid);
209 : }
210 :
211 : /* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */
212 426339 : NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval)
213 : {
214 426339 : NS_ASSERTION(iid, "bad param");
215 426339 : NS_ASSERTION(_retval, "bad param");
216 :
217 852678 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
218 426339 : xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
219 426339 : return EntryToInfo(entry, _retval);
220 : }
221 :
222 : /* nsIInterfaceInfo getInfoForName (in string name); */
223 98330 : NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval)
224 : {
225 98330 : NS_ASSERTION(name, "bad param");
226 98330 : NS_ASSERTION(_retval, "bad param");
227 :
228 196660 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
229 98330 : xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
230 98330 : return EntryToInfo(entry, _retval);
231 : }
232 :
233 : /* nsIIDPtr getIIDForName (in string name); */
234 0 : NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval)
235 : {
236 0 : NS_ASSERTION(name, "bad param");
237 0 : NS_ASSERTION(_retval, "bad param");
238 :
239 0 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
240 0 : xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
241 0 : if (!entry) {
242 0 : *_retval = nsnull;
243 0 : return NS_ERROR_FAILURE;
244 : }
245 :
246 0 : return entry->GetIID(_retval);
247 : }
248 :
249 : /* string getNameForIID (in nsIIDPtr iid); */
250 0 : NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval)
251 : {
252 0 : NS_ASSERTION(iid, "bad param");
253 0 : NS_ASSERTION(_retval, "bad param");
254 :
255 0 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
256 0 : xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
257 0 : if (!entry) {
258 0 : *_retval = nsnull;
259 0 : return NS_ERROR_FAILURE;
260 : }
261 :
262 0 : return entry->GetName(_retval);
263 : }
264 :
265 : static PLDHashOperator
266 0 : xpti_ArrayAppender(const char* name, xptiInterfaceEntry* entry, void* arg)
267 : {
268 0 : nsISupportsArray* array = (nsISupportsArray*) arg;
269 :
270 0 : nsCOMPtr<nsIInterfaceInfo> ii;
271 0 : if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii))))
272 0 : array->AppendElement(ii);
273 0 : return PL_DHASH_NEXT;
274 : }
275 :
276 : /* nsIEnumerator enumerateInterfaces (); */
277 0 : NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval)
278 : {
279 : // I didn't want to incur the size overhead of using nsHashtable just to
280 : // make building an enumerator easier. So, this code makes a snapshot of
281 : // the table using an nsISupportsArray and builds an enumerator for that.
282 : // We can afford this transient cost.
283 :
284 0 : nsCOMPtr<nsISupportsArray> array;
285 0 : NS_NewISupportsArray(getter_AddRefs(array));
286 0 : if (!array)
287 0 : return NS_ERROR_UNEXPECTED;
288 :
289 0 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
290 0 : mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, array);
291 :
292 0 : return array->Enumerate(_retval);
293 : }
294 :
295 : struct ArrayAndPrefix
296 : {
297 : nsISupportsArray* array;
298 : const char* prefix;
299 : PRUint32 length;
300 : };
301 :
302 : static PLDHashOperator
303 465732 : xpti_ArrayPrefixAppender(const char* keyname, xptiInterfaceEntry* entry, void* arg)
304 : {
305 465732 : ArrayAndPrefix* args = (ArrayAndPrefix*) arg;
306 :
307 465732 : const char* name = entry->GetTheName();
308 465732 : if (name != PL_strnstr(name, args->prefix, args->length))
309 335682 : return PL_DHASH_NEXT;
310 :
311 260100 : nsCOMPtr<nsIInterfaceInfo> ii;
312 130050 : if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii))))
313 130050 : args->array->AppendElement(ii);
314 130050 : return PL_DHASH_NEXT;
315 : }
316 :
317 : /* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */
318 306 : NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval)
319 : {
320 612 : nsCOMPtr<nsISupportsArray> array;
321 306 : NS_NewISupportsArray(getter_AddRefs(array));
322 306 : if (!array)
323 0 : return NS_ERROR_UNEXPECTED;
324 :
325 612 : ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
326 306 : ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)};
327 306 : mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayPrefixAppender, &args);
328 :
329 306 : return array->Enumerate(_retval);
330 : }
331 :
332 : /* void autoRegisterInterfaces (); */
333 0 : NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces()
334 : {
335 : NS_TIME_FUNCTION;
336 :
337 0 : return NS_ERROR_NOT_IMPLEMENTED;
338 : }
339 :
340 : /***************************************************************************/
341 :
342 : /* void addAdditionalManager (in nsIInterfaceInfoManager manager); */
343 0 : NS_IMETHODIMP xptiInterfaceInfoManager::AddAdditionalManager(nsIInterfaceInfoManager *manager)
344 : {
345 0 : nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(manager);
346 : nsISupports* ptrToAdd = weakRef ?
347 0 : static_cast<nsISupports*>(weakRef) :
348 0 : static_cast<nsISupports*>(manager);
349 : { // scoped lock...
350 0 : MutexAutoLock lock(mAdditionalManagersLock);
351 0 : if (mAdditionalManagers.IndexOf(ptrToAdd) != -1)
352 0 : return NS_ERROR_FAILURE;
353 0 : if (!mAdditionalManagers.AppendObject(ptrToAdd))
354 0 : return NS_ERROR_OUT_OF_MEMORY;
355 : }
356 0 : return NS_OK;
357 : }
358 :
359 : /* void removeAdditionalManager (in nsIInterfaceInfoManager manager); */
360 0 : NS_IMETHODIMP xptiInterfaceInfoManager::RemoveAdditionalManager(nsIInterfaceInfoManager *manager)
361 : {
362 0 : nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(manager);
363 : nsISupports* ptrToRemove = weakRef ?
364 0 : static_cast<nsISupports*>(weakRef) :
365 0 : static_cast<nsISupports*>(manager);
366 : { // scoped lock...
367 0 : MutexAutoLock lock(mAdditionalManagersLock);
368 0 : if (!mAdditionalManagers.RemoveObject(ptrToRemove))
369 0 : return NS_ERROR_FAILURE;
370 : }
371 0 : return NS_OK;
372 : }
373 :
374 : /* bool hasAdditionalManagers (); */
375 7439 : NS_IMETHODIMP xptiInterfaceInfoManager::HasAdditionalManagers(bool *_retval)
376 : {
377 7439 : *_retval = mAdditionalManagers.Count() > 0;
378 7439 : return NS_OK;
379 : }
380 :
381 : /* nsISimpleEnumerator enumerateAdditionalManagers (); */
382 0 : NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateAdditionalManagers(nsISimpleEnumerator **_retval)
383 : {
384 0 : MutexAutoLock lock(mAdditionalManagersLock);
385 :
386 0 : nsCOMArray<nsISupports> managerArray(mAdditionalManagers);
387 : /* Resolve all the weak references in the array. */
388 0 : for(PRInt32 i = managerArray.Count(); i--; ) {
389 0 : nsISupports *raw = managerArray.ObjectAt(i);
390 0 : if (!raw)
391 0 : return NS_ERROR_FAILURE;
392 0 : nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(raw);
393 0 : if (weakRef) {
394 : nsCOMPtr<nsIInterfaceInfoManager> manager =
395 0 : do_QueryReferent(weakRef);
396 0 : if (manager) {
397 0 : if (!managerArray.ReplaceObjectAt(manager, i))
398 0 : return NS_ERROR_FAILURE;
399 : }
400 : else {
401 : // The manager is no more. Remove the element.
402 0 : mAdditionalManagers.RemoveObjectAt(i);
403 0 : managerArray.RemoveObjectAt(i);
404 : }
405 : }
406 : }
407 :
408 0 : return NS_NewArrayEnumerator(_retval, managerArray);
409 : }
|