xref: /reactos/dll/win32/wmiutils/path.c (revision 4561998a)
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #define COBJMACROS
20 
21 #include "config.h"
22 #include <stdarg.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "wbemcli.h"
28 #include "wmiutils.h"
29 
30 #include "wine/debug.h"
31 #include "wmiutils_private.h"
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(wmiutils);
34 
35 struct keylist
36 {
37     IWbemPathKeyList IWbemPathKeyList_iface;
38     IWbemPath       *parent;
39     LONG             refs;
40 };
41 
42 struct key
43 {
44     WCHAR *name;
45     int    len_name;
46     WCHAR *value;
47     int    len_value;
48 };
49 
50 struct path
51 {
52     IWbemPath        IWbemPath_iface;
53     LONG             refs;
54     CRITICAL_SECTION cs;
55     WCHAR           *text;
56     int              len_text;
57     WCHAR           *server;
58     int              len_server;
59     WCHAR          **namespaces;
60     int             *len_namespaces;
61     int              num_namespaces;
62     WCHAR           *class;
63     int              len_class;
64     struct key      *keys;
65     unsigned int     num_keys;
66     ULONGLONG        flags;
67 };
68 
69 static inline struct keylist *impl_from_IWbemPathKeyList( IWbemPathKeyList *iface )
70 {
71     return CONTAINING_RECORD(iface, struct keylist, IWbemPathKeyList_iface);
72 }
73 
74 static inline struct path *impl_from_IWbemPath( IWbemPath *iface )
75 {
76     return CONTAINING_RECORD(iface, struct path, IWbemPath_iface);
77 }
78 
79 static ULONG WINAPI keylist_AddRef(
80     IWbemPathKeyList *iface )
81 {
82     struct keylist *keylist = impl_from_IWbemPathKeyList( iface );
83     return InterlockedIncrement( &keylist->refs );
84 }
85 
86 static ULONG WINAPI keylist_Release(
87     IWbemPathKeyList *iface )
88 {
89     struct keylist *keylist = impl_from_IWbemPathKeyList( iface );
90     LONG refs = InterlockedDecrement( &keylist->refs );
91     if (!refs)
92     {
93         TRACE("destroying %p\n", keylist);
94         IWbemPath_Release( keylist->parent );
95         heap_free( keylist );
96     }
97     return refs;
98 }
99 
100 static HRESULT WINAPI keylist_QueryInterface(
101     IWbemPathKeyList *iface,
102     REFIID riid,
103     void **ppvObject )
104 {
105     struct keylist *keylist = impl_from_IWbemPathKeyList( iface );
106 
107     TRACE("%p, %s, %p\n", keylist, debugstr_guid(riid), ppvObject);
108 
109     if (IsEqualGUID( riid, &IID_IWbemPathKeyList ) ||
110         IsEqualGUID( riid, &IID_IUnknown ))
111     {
112         *ppvObject = iface;
113     }
114     else
115     {
116         FIXME("interface %s not implemented\n", debugstr_guid(riid));
117         return E_NOINTERFACE;
118     }
119     IWbemPathKeyList_AddRef( iface );
120     return S_OK;
121 }
122 
123 static HRESULT WINAPI keylist_GetCount(
124     IWbemPathKeyList *iface,
125     ULONG *puKeyCount )
126 {
127     struct keylist *keylist = impl_from_IWbemPathKeyList( iface );
128     struct path *parent = impl_from_IWbemPath( keylist->parent );
129 
130     TRACE("%p, %p\n", iface, puKeyCount);
131 
132     if (!puKeyCount) return WBEM_E_INVALID_PARAMETER;
133 
134     EnterCriticalSection( &parent->cs );
135 
136     *puKeyCount = parent->num_keys;
137 
138     LeaveCriticalSection( &parent->cs );
139     return S_OK;
140 }
141 
142 static HRESULT WINAPI keylist_SetKey(
143     IWbemPathKeyList *iface,
144     LPCWSTR wszName,
145     ULONG uFlags,
146     ULONG uCimType,
147     LPVOID pKeyVal )
148 {
149     FIXME("%p, %s, 0x%x, %u, %p\n", iface, debugstr_w(wszName), uFlags, uCimType, pKeyVal);
150     return E_NOTIMPL;
151 }
152 
153 static HRESULT WINAPI keylist_SetKey2(
154     IWbemPathKeyList *iface,
155     LPCWSTR wszName,
156     ULONG uFlags,
157     ULONG uCimType,
158     VARIANT *pKeyVal )
159 {
160     FIXME("%p, %s, 0x%x, %u, %p\n", iface, debugstr_w(wszName), uFlags, uCimType, pKeyVal);
161     return E_NOTIMPL;
162 }
163 
164 static HRESULT WINAPI keylist_GetKey(
165     IWbemPathKeyList *iface,
166     ULONG uKeyIx,
167     ULONG uFlags,
168     ULONG *puNameBufSize,
169     LPWSTR pszKeyName,
170     ULONG *puKeyValBufSize,
171     LPVOID pKeyVal,
172     ULONG *puApparentCimType )
173 {
174     FIXME("%p, %u, 0x%x, %p, %p, %p, %p, %p\n", iface, uKeyIx, uFlags, puNameBufSize,
175           pszKeyName, puKeyValBufSize, pKeyVal, puApparentCimType);
176     return E_NOTIMPL;
177 }
178 
179 static HRESULT WINAPI keylist_GetKey2(
180     IWbemPathKeyList *iface,
181     ULONG uKeyIx,
182     ULONG uFlags,
183     ULONG *puNameBufSize,
184     LPWSTR pszKeyName,
185     VARIANT *pKeyValue,
186     ULONG *puApparentCimType )
187 {
188     FIXME("%p, %u, 0x%x, %p, %p, %p, %p\n", iface, uKeyIx, uFlags, puNameBufSize,
189           pszKeyName, pKeyValue, puApparentCimType);
190     return E_NOTIMPL;
191 }
192 
193 static HRESULT WINAPI keylist_RemoveKey(
194     IWbemPathKeyList *iface,
195     LPCWSTR wszName,
196     ULONG uFlags )
197 {
198     FIXME("%p, %s, 0x%x\n", iface, debugstr_w(wszName), uFlags);
199     return E_NOTIMPL;
200 }
201 
202 static void free_keys( struct key *keys, unsigned int count )
203 {
204     unsigned int i;
205 
206     for (i = 0; i < count; i++)
207     {
208         heap_free( keys[i].name );
209         heap_free( keys[i].value );
210     }
211     heap_free( keys );
212 }
213 
214 static HRESULT WINAPI keylist_RemoveAllKeys(
215     IWbemPathKeyList *iface,
216     ULONG uFlags )
217 {
218     struct keylist *keylist = impl_from_IWbemPathKeyList( iface );
219     struct path *parent = impl_from_IWbemPath( keylist->parent );
220 
221     TRACE("%p, 0x%x\n", iface, uFlags);
222 
223     if (uFlags) return WBEM_E_INVALID_PARAMETER;
224 
225     EnterCriticalSection( &parent->cs );
226 
227     free_keys( parent->keys, parent->num_keys );
228     parent->num_keys = 0;
229     parent->keys = NULL;
230 
231     LeaveCriticalSection( &parent->cs );
232     return S_OK;
233 }
234 
235 static HRESULT WINAPI keylist_MakeSingleton(
236     IWbemPathKeyList *iface,
237     boolean bSet )
238 {
239     FIXME("%p, %d\n", iface, bSet);
240     return E_NOTIMPL;
241 }
242 
243 static HRESULT WINAPI keylist_GetInfo(
244     IWbemPathKeyList *iface,
245     ULONG uRequestedInfo,
246     ULONGLONG *puResponse )
247 {
248     FIXME("%p, %u, %p\n", iface, uRequestedInfo, puResponse);
249     return E_NOTIMPL;
250 }
251 
252 static HRESULT WINAPI keylist_GetText(
253     IWbemPathKeyList *iface,
254     LONG lFlags,
255     ULONG *puBuffLength,
256     LPWSTR pszText )
257 {
258     FIXME("%p, 0x%x, %p, %p\n", iface, lFlags, puBuffLength, pszText);
259     return E_NOTIMPL;
260 }
261 
262 static const struct IWbemPathKeyListVtbl keylist_vtbl =
263 {
264     keylist_QueryInterface,
265     keylist_AddRef,
266     keylist_Release,
267     keylist_GetCount,
268     keylist_SetKey,
269     keylist_SetKey2,
270     keylist_GetKey,
271     keylist_GetKey2,
272     keylist_RemoveKey,
273     keylist_RemoveAllKeys,
274     keylist_MakeSingleton,
275     keylist_GetInfo,
276     keylist_GetText
277 };
278 
279 static HRESULT WbemPathKeyList_create( IWbemPath *parent, LPVOID *ppObj )
280 {
281     struct keylist *keylist;
282 
283     TRACE("%p\n", ppObj);
284 
285     if (!(keylist = heap_alloc( sizeof(*keylist) ))) return E_OUTOFMEMORY;
286 
287     keylist->IWbemPathKeyList_iface.lpVtbl = &keylist_vtbl;
288     keylist->refs = 1;
289     keylist->parent = parent;
290     IWbemPath_AddRef( keylist->parent );
291 
292     *ppObj = &keylist->IWbemPathKeyList_iface;
293 
294     TRACE("returning iface %p\n", *ppObj);
295     return S_OK;
296 }
297 
298 static void init_path( struct path *path )
299 {
300     path->text           = NULL;
301     path->len_text       = 0;
302     path->server         = NULL;
303     path->len_server     = 0;
304     path->namespaces     = NULL;
305     path->len_namespaces = NULL;
306     path->num_namespaces = 0;
307     path->class          = NULL;
308     path->len_class      = 0;
309     path->keys           = NULL;
310     path->num_keys       = 0;
311     path->flags          = 0;
312 }
313 
314 static void clear_path( struct path *path )
315 {
316     unsigned int i;
317 
318     heap_free( path->text );
319     heap_free( path->server );
320     for (i = 0; i < path->num_namespaces; i++) heap_free( path->namespaces[i] );
321     heap_free( path->namespaces );
322     heap_free( path->len_namespaces );
323     heap_free( path->class );
324     free_keys( path->keys, path->num_keys );
325     init_path( path );
326 }
327 
328 static ULONG WINAPI path_AddRef(
329     IWbemPath *iface )
330 {
331     struct path *path = impl_from_IWbemPath( iface );
332     return InterlockedIncrement( &path->refs );
333 }
334 
335 static ULONG WINAPI path_Release(
336     IWbemPath *iface )
337 {
338     struct path *path = impl_from_IWbemPath( iface );
339     LONG refs = InterlockedDecrement( &path->refs );
340     if (!refs)
341     {
342         TRACE("destroying %p\n", path);
343         clear_path( path );
344         path->cs.DebugInfo->Spare[0] = 0;
345         DeleteCriticalSection( &path->cs );
346         heap_free( path );
347     }
348     return refs;
349 }
350 
351 static HRESULT WINAPI path_QueryInterface(
352     IWbemPath *iface,
353     REFIID riid,
354     void **ppvObject )
355 {
356     struct path *path = impl_from_IWbemPath( iface );
357 
358     TRACE("%p, %s, %p\n", path, debugstr_guid( riid ), ppvObject );
359 
360     if ( IsEqualGUID( riid, &IID_IWbemPath ) ||
361          IsEqualGUID( riid, &IID_IUnknown ) )
362     {
363         *ppvObject = iface;
364     }
365     else
366     {
367         FIXME("interface %s not implemented\n", debugstr_guid(riid));
368         return E_NOINTERFACE;
369     }
370     IWbemPath_AddRef( iface );
371     return S_OK;
372 }
373 
374 static HRESULT parse_key( struct key *key, const WCHAR *str, unsigned int *ret_len )
375 {
376     const WCHAR *p, *q;
377     unsigned int len;
378 
379     p = q = str;
380     while (*q && *q != '=')
381     {
382         if (*q == ',' || isspaceW( *q )) return WBEM_E_INVALID_PARAMETER;
383         q++;
384     }
385     len = q - p;
386     if (!(key->name = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
387     memcpy( key->name, p, len * sizeof(WCHAR) );
388     key->name[len] = 0;
389     key->len_name = len;
390 
391     p = ++q;
392     if (!*p || *p == ',' || isspaceW( *p )) return WBEM_E_INVALID_PARAMETER;
393 
394     while (*q && *q != ',') q++;
395     len = q - p;
396     if (!(key->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
397     memcpy( key->value, p, len * sizeof(WCHAR) );
398     key->value[len] = 0;
399     key->len_value = len;
400 
401     *ret_len = q - str;
402     if (*q == ',') (*ret_len)++;
403     return S_OK;
404 }
405 
406 static HRESULT parse_text( struct path *path, ULONG mode, const WCHAR *text )
407 {
408     HRESULT hr = E_OUTOFMEMORY;
409     const WCHAR *p, *q;
410     unsigned int i, len;
411 
412     p = q = text;
413     if ((p[0] == '\\' && p[1] == '\\') || (p[0] == '/' && p[1] == '/'))
414     {
415         p += 2;
416         q = p;
417         while (*q && *q != '\\' && *q != '/') q++;
418         len = q - p;
419         if (!(path->server = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
420         memcpy( path->server, p, len * sizeof(WCHAR) );
421         path->server[len] = 0;
422         path->len_server = len;
423         path->flags |= WBEMPATH_INFO_PATH_HAD_SERVER;
424     }
425     p = q;
426     if (strchrW( p, '\\' ) || strchrW( p, '/' ))
427     {
428         if (*q != '\\' && *q != '/' && *q != ':')
429         {
430             path->num_namespaces = 1;
431             q++;
432         }
433         while (*q && *q != ':')
434         {
435             if (*q == '\\' || *q == '/') path->num_namespaces++;
436             q++;
437         }
438     }
439     if (path->num_namespaces)
440     {
441         if (!(path->namespaces = heap_alloc( path->num_namespaces * sizeof(WCHAR *) ))) goto done;
442         if (!(path->len_namespaces = heap_alloc( path->num_namespaces * sizeof(int) ))) goto done;
443 
444         i = 0;
445         q = p;
446         if (*q && *q != '\\' && *q != '/' && *q != ':')
447         {
448             p = q;
449             while (*p && *p != '\\' && *p != '/' && *p != ':') p++;
450             len = p - q;
451             if (!(path->namespaces[i] = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
452             memcpy( path->namespaces[i], q, len * sizeof(WCHAR) );
453             path->namespaces[i][len] = 0;
454             path->len_namespaces[i] = len;
455             q = p;
456             i++;
457         }
458         while (*q && *q != ':')
459         {
460             if (*q == '\\' || *q == '/')
461             {
462                 p = q + 1;
463                 while (*p && *p != '\\' && *p != '/' && *p != ':') p++;
464                 len = p - q - 1;
465                 if (!(path->namespaces[i] = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
466                 memcpy( path->namespaces[i], q + 1, len * sizeof(WCHAR) );
467                 path->namespaces[i][len] = 0;
468                 path->len_namespaces[i] = len;
469                 i++;
470             }
471             q++;
472         }
473     }
474     if (*q == ':') q++;
475     p = q;
476     while (*q && *q != '.') q++;
477     len = q - p;
478     if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
479     memcpy( path->class, p, len * sizeof(WCHAR) );
480     path->class[len] = 0;
481     path->len_class = len;
482 
483     if (*q == '.')
484     {
485         p = ++q;
486         path->num_keys++;
487         while (*q)
488         {
489             if (*q == ',') path->num_keys++;
490             q++;
491         }
492         if (!(path->keys = heap_alloc_zero( path->num_keys * sizeof(struct key) ))) goto done;
493         i = 0;
494         q = p;
495         while (*q)
496         {
497             if (i >= path->num_keys) break;
498             hr = parse_key( &path->keys[i], q, &len );
499             if (hr != S_OK) goto done;
500             q += len;
501             i++;
502         }
503     }
504     hr = S_OK;
505 
506 done:
507     if (hr != S_OK) clear_path( path );
508     else path->flags |= WBEMPATH_INFO_CIM_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT;
509     return hr;
510 }
511 
512 static HRESULT WINAPI path_SetText(
513     IWbemPath *iface,
514     ULONG uMode,
515     LPCWSTR pszPath)
516 {
517     struct path *path = impl_from_IWbemPath( iface );
518     HRESULT hr = S_OK;
519     int len;
520 
521     TRACE("%p, %u, %s\n", iface, uMode, debugstr_w(pszPath));
522 
523     if (!uMode || !pszPath) return WBEM_E_INVALID_PARAMETER;
524 
525     EnterCriticalSection( &path->cs );
526 
527     clear_path( path );
528     if (!pszPath[0]) goto done;
529     if ((hr = parse_text( path, uMode, pszPath )) != S_OK) goto done;
530 
531     len = strlenW( pszPath );
532     if (!(path->text = heap_alloc( (len + 1) * sizeof(WCHAR) )))
533     {
534         clear_path( path );
535         hr = E_OUTOFMEMORY;
536         goto done;
537     }
538     strcpyW( path->text, pszPath );
539     path->len_text = len;
540 
541 done:
542     LeaveCriticalSection( &path->cs );
543     return hr;
544 }
545 
546 static WCHAR *build_namespace( struct path *path, int *len, BOOL leading_slash )
547 {
548     WCHAR *ret, *p;
549     int i;
550 
551     *len = 0;
552     for (i = 0; i < path->num_namespaces; i++)
553     {
554         if (i > 0 || leading_slash) *len += 1;
555         *len += path->len_namespaces[i];
556     }
557     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
558     for (i = 0; i < path->num_namespaces; i++)
559     {
560         if (i > 0 || leading_slash) *p++ = '\\';
561         memcpy( p, path->namespaces[i], path->len_namespaces[i] * sizeof(WCHAR) );
562         p += path->len_namespaces[i];
563     }
564     *p = 0;
565     return ret;
566 }
567 
568 static WCHAR *build_server( struct path *path, int *len )
569 {
570     WCHAR *ret, *p;
571 
572     *len = 0;
573     if (path->len_server) *len += 2 + path->len_server;
574     else *len += 3;
575     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
576     if (path->len_server)
577     {
578         p[0] = p[1] = '\\';
579         strcpyW( p + 2, path->server );
580     }
581     else
582     {
583         p[0] = p[1] = '\\';
584         p[2] = '.';
585         p[3] = 0;
586     }
587     return ret;
588 }
589 
590 static WCHAR *build_keylist( struct path *path, int *len )
591 {
592     WCHAR *ret, *p;
593     unsigned int i;
594 
595     *len = 0;
596     for (i = 0; i < path->num_keys; i++)
597     {
598         if (i > 0) *len += 1;
599         *len += path->keys[i].len_name + path->keys[i].len_value + 1;
600     }
601     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
602     for (i = 0; i < path->num_keys; i++)
603     {
604         if (i > 0) *p++ = ',';
605         memcpy( p, path->keys[i].name, path->keys[i].len_name * sizeof(WCHAR) );
606         p += path->keys[i].len_name;
607         *p++ = '=';
608         memcpy( p, path->keys[i].value, path->keys[i].len_value * sizeof(WCHAR) );
609         p += path->keys[i].len_value;
610     }
611     *p = 0;
612     return ret;
613 }
614 
615 static WCHAR *build_path( struct path *path, LONG flags, int *len )
616 {
617     *len = 0;
618     switch (flags)
619     {
620     case 0:
621     {
622         int len_namespace, len_keylist;
623         WCHAR *ret, *namespace = build_namespace( path, &len_namespace, FALSE );
624         WCHAR *keylist = build_keylist( path, &len_keylist );
625 
626         if (!namespace || !keylist)
627         {
628             heap_free( namespace );
629             heap_free( keylist );
630             return NULL;
631         }
632         *len = len_namespace;
633         if (path->len_class)
634         {
635             *len += path->len_class + 1;
636             if (path->num_keys) *len += len_keylist + 1;
637         }
638         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
639         {
640             heap_free( namespace );
641             heap_free( keylist );
642             return NULL;
643         }
644         strcpyW( ret, namespace );
645         if (path->len_class)
646         {
647             ret[len_namespace] = ':';
648             strcpyW( ret + len_namespace + 1, path->class );
649             if (path->num_keys)
650             {
651                 ret[len_namespace + path->len_class + 1] = '.';
652                 strcpyW( ret + len_namespace + path->len_class + 2, keylist );
653             }
654         }
655         heap_free( namespace );
656         heap_free( keylist );
657         return ret;
658 
659     }
660     case WBEMPATH_GET_RELATIVE_ONLY:
661     {
662         int len_keylist;
663         WCHAR *ret, *keylist;
664 
665         if (!path->len_class) return NULL;
666         if (!(keylist = build_keylist( path, &len_keylist ))) return NULL;
667 
668         *len = path->len_class;
669         if (path->num_keys) *len += len_keylist + 1;
670         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
671         {
672             heap_free( keylist );
673             return NULL;
674         }
675         strcpyW( ret, path->class );
676         if (path->num_keys)
677         {
678             ret[path->len_class] = '.';
679             strcpyW( ret + path->len_class + 1, keylist );
680         }
681         heap_free( keylist );
682         return ret;
683     }
684     case WBEMPATH_GET_SERVER_TOO:
685     {
686         int len_namespace, len_server, len_keylist;
687         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
688         WCHAR *server = build_server( path, &len_server );
689         WCHAR *keylist = build_keylist( path, &len_keylist );
690 
691         if (!namespace || !server || !keylist)
692         {
693             heap_free( namespace );
694             heap_free( server );
695             heap_free( keylist );
696             return NULL;
697         }
698         *len = len_namespace + len_server;
699         if (path->len_class)
700         {
701             *len += path->len_class + 1;
702             if (path->num_keys) *len += len_keylist + 1;
703         }
704         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
705         {
706             heap_free( namespace );
707             heap_free( server );
708             heap_free( keylist );
709             return NULL;
710         }
711         strcpyW( p, server );
712         p += len_server;
713         strcpyW( p, namespace );
714         p += len_namespace;
715         if (path->len_class)
716         {
717             *p++ = ':';
718             strcpyW( p, path->class );
719             if (path->num_keys)
720             {
721                 p[path->len_class] = '.';
722                 strcpyW( p + path->len_class + 1, keylist );
723             }
724         }
725         heap_free( namespace );
726         heap_free( server );
727         heap_free( keylist );
728         return ret;
729     }
730     case WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY:
731     {
732         int len_namespace, len_server;
733         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
734         WCHAR *server = build_server( path, &len_server );
735 
736         if (!namespace || !server)
737         {
738             heap_free( namespace );
739             heap_free( server );
740             return NULL;
741         }
742         *len = len_namespace + len_server;
743         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
744         {
745             heap_free( namespace );
746             heap_free( server );
747             return NULL;
748         }
749         strcpyW( p, server );
750         p += len_server;
751         strcpyW( p, namespace );
752         heap_free( namespace );
753         heap_free( server );
754         return ret;
755     }
756     case WBEMPATH_GET_NAMESPACE_ONLY:
757         return build_namespace( path, len, FALSE );
758 
759     case WBEMPATH_GET_ORIGINAL:
760         if (!path->len_text) return NULL;
761         *len = path->len_text;
762         return strdupW( path->text );
763 
764     default:
765         ERR("unhandled flags 0x%x\n", flags);
766         return NULL;
767     }
768 }
769 
770 static HRESULT WINAPI path_GetText(
771     IWbemPath *iface,
772     LONG lFlags,
773     ULONG *puBufferLength,
774     LPWSTR pszText)
775 {
776     struct path *path = impl_from_IWbemPath( iface );
777     HRESULT hr = S_OK;
778     WCHAR *str;
779     int len;
780 
781     TRACE("%p, 0x%x, %p, %p\n", iface, lFlags, puBufferLength, pszText);
782 
783     if (!puBufferLength) return WBEM_E_INVALID_PARAMETER;
784 
785     EnterCriticalSection( &path->cs );
786 
787     str = build_path( path, lFlags, &len );
788     if (*puBufferLength < len + 1)
789     {
790         *puBufferLength = len + 1;
791         goto done;
792     }
793     if (!pszText)
794     {
795         hr = WBEM_E_INVALID_PARAMETER;
796         goto done;
797     }
798     if (str) strcpyW( pszText, str );
799     else pszText[0] = 0;
800     *puBufferLength = len + 1;
801 
802     TRACE("returning %s\n", debugstr_w(pszText));
803 
804 done:
805     heap_free( str );
806     LeaveCriticalSection( &path->cs );
807     return hr;
808 }
809 
810 static HRESULT WINAPI path_GetInfo(
811     IWbemPath *iface,
812     ULONG info,
813     ULONGLONG *response)
814 {
815     struct path *path = impl_from_IWbemPath( iface );
816 
817     TRACE("%p, %u, %p\n", iface, info, response);
818 
819     if (info || !response) return WBEM_E_INVALID_PARAMETER;
820 
821     FIXME("some flags are not implemented\n");
822 
823     EnterCriticalSection( &path->cs );
824 
825     *response = path->flags;
826     if (!path->server || (path->len_server == 1 && path->server[0] == '.'))
827         *response |= WBEMPATH_INFO_ANON_LOCAL_MACHINE;
828     else
829         *response |= WBEMPATH_INFO_HAS_MACHINE_NAME;
830 
831     if (!path->class)
832         *response |= WBEMPATH_INFO_SERVER_NAMESPACE_ONLY;
833     else
834     {
835         *response |= WBEMPATH_INFO_HAS_SUBSCOPES;
836         if (path->num_keys)
837             *response |= WBEMPATH_INFO_IS_INST_REF;
838         else
839             *response |= WBEMPATH_INFO_IS_CLASS_REF;
840     }
841 
842     LeaveCriticalSection( &path->cs );
843     return S_OK;
844 }
845 
846 static HRESULT WINAPI path_SetServer(
847     IWbemPath *iface,
848     LPCWSTR name)
849 {
850     struct path *path = impl_from_IWbemPath( iface );
851     static const ULONGLONG flags =
852         WBEMPATH_INFO_PATH_HAD_SERVER | WBEMPATH_INFO_V1_COMPLIANT |
853         WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
854     WCHAR *server;
855 
856     TRACE("%p, %s\n", iface, debugstr_w(name));
857 
858     EnterCriticalSection( &path->cs );
859 
860     if (name)
861     {
862         if (!(server = strdupW( name )))
863         {
864             LeaveCriticalSection( &path->cs );
865             return WBEM_E_OUT_OF_MEMORY;
866         }
867         heap_free( path->server );
868         path->server = server;
869         path->len_server = strlenW( path->server );
870         path->flags |= flags;
871     }
872     else
873     {
874         heap_free( path->server );
875         path->server = NULL;
876         path->len_server = 0;
877         path->flags &= ~flags;
878     }
879 
880     LeaveCriticalSection( &path->cs );
881     return S_OK;
882 }
883 
884 static HRESULT WINAPI path_GetServer(
885     IWbemPath *iface,
886     ULONG *len,
887     LPWSTR name)
888 {
889     struct path *path = impl_from_IWbemPath( iface );
890 
891     TRACE("%p, %p, %p\n", iface, len, name);
892 
893     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
894 
895     EnterCriticalSection( &path->cs );
896 
897     if (!path->server)
898     {
899         LeaveCriticalSection( &path->cs );
900         return WBEM_E_NOT_AVAILABLE;
901     }
902     if (*len > path->len_server) strcpyW( name, path->server );
903     *len = path->len_server + 1;
904 
905     LeaveCriticalSection( &path->cs );
906     return S_OK;
907 }
908 
909 static HRESULT WINAPI path_GetNamespaceCount(
910     IWbemPath *iface,
911     ULONG *puCount)
912 {
913     struct path *path = impl_from_IWbemPath( iface );
914 
915     TRACE("%p, %p\n", iface, puCount);
916 
917     if (!puCount) return WBEM_E_INVALID_PARAMETER;
918 
919     EnterCriticalSection( &path->cs );
920     *puCount = path->num_namespaces;
921     LeaveCriticalSection( &path->cs );
922     return S_OK;
923 }
924 
925 static HRESULT WINAPI path_SetNamespaceAt(
926     IWbemPath *iface,
927     ULONG idx,
928     LPCWSTR name)
929 {
930     struct path *path = impl_from_IWbemPath( iface );
931     static const ULONGLONG flags =
932         WBEMPATH_INFO_V1_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT |
933         WBEMPATH_INFO_CIM_COMPLIANT;
934     int i, *tmp_len;
935     WCHAR **tmp, *new;
936     DWORD size;
937 
938     TRACE("%p, %u, %s\n", iface, idx, debugstr_w(name));
939 
940     EnterCriticalSection( &path->cs );
941 
942     if (idx > path->num_namespaces || !name)
943     {
944         LeaveCriticalSection( &path->cs );
945         return WBEM_E_INVALID_PARAMETER;
946     }
947     if (!(new = strdupW( name )))
948     {
949         LeaveCriticalSection( &path->cs );
950         return WBEM_E_OUT_OF_MEMORY;
951     }
952     size = (path->num_namespaces + 1) * sizeof(WCHAR *);
953     if (path->namespaces) tmp = heap_realloc( path->namespaces, size );
954     else tmp = heap_alloc( size );
955     if (!tmp)
956     {
957         heap_free( new );
958         LeaveCriticalSection( &path->cs );
959         return WBEM_E_OUT_OF_MEMORY;
960     }
961     path->namespaces = tmp;
962     size = (path->num_namespaces + 1) * sizeof(int);
963     if (path->len_namespaces) tmp_len = heap_realloc( path->len_namespaces, size );
964     else tmp_len = heap_alloc( size );
965     if (!tmp_len)
966     {
967         heap_free( new );
968         LeaveCriticalSection( &path->cs );
969         return WBEM_E_OUT_OF_MEMORY;
970     }
971     path->len_namespaces = tmp_len;
972     for (i = idx; i < path->num_namespaces; i++)
973     {
974         path->namespaces[i + 1] = path->namespaces[i];
975         path->len_namespaces[i + 1] = path->len_namespaces[i];
976     }
977     path->namespaces[idx] = new;
978     path->len_namespaces[idx] = strlenW( new );
979     path->num_namespaces++;
980     path->flags |= flags;
981 
982     LeaveCriticalSection( &path->cs );
983     return S_OK;
984 }
985 
986 static HRESULT WINAPI path_GetNamespaceAt(
987     IWbemPath *iface,
988     ULONG idx,
989     ULONG *len,
990     LPWSTR name)
991 {
992     struct path *path = impl_from_IWbemPath( iface );
993 
994     TRACE("%p, %u, %p, %p\n", iface, idx, len, name);
995 
996     EnterCriticalSection( &path->cs );
997 
998     if (!len || (*len && !name) || idx >= path->num_namespaces)
999     {
1000         LeaveCriticalSection( &path->cs );
1001         return WBEM_E_INVALID_PARAMETER;
1002     }
1003     if (*len > path->len_namespaces[idx]) strcpyW( name, path->namespaces[idx] );
1004     *len = path->len_namespaces[idx] + 1;
1005 
1006     LeaveCriticalSection( &path->cs );
1007     return S_OK;
1008 }
1009 
1010 static HRESULT WINAPI path_RemoveNamespaceAt(
1011     IWbemPath *iface,
1012     ULONG idx)
1013 {
1014     struct path *path = impl_from_IWbemPath( iface );
1015 
1016     TRACE("%p, %u\n", iface, idx);
1017 
1018     EnterCriticalSection( &path->cs );
1019 
1020     if (idx >= path->num_namespaces)
1021     {
1022         LeaveCriticalSection( &path->cs );
1023         return WBEM_E_INVALID_PARAMETER;
1024     }
1025     heap_free( path->namespaces[idx] );
1026     while (idx < path->num_namespaces - 1)
1027     {
1028         path->namespaces[idx] = path->namespaces[idx + 1];
1029         path->len_namespaces[idx] = path->len_namespaces[idx + 1];
1030         idx++;
1031     }
1032     path->num_namespaces--;
1033 
1034     LeaveCriticalSection( &path->cs );
1035     return S_OK;
1036 }
1037 
1038 static HRESULT WINAPI path_RemoveAllNamespaces(
1039     IWbemPath *iface)
1040 {
1041     struct path *path = impl_from_IWbemPath( iface );
1042     int i;
1043 
1044     TRACE("%p\n", iface);
1045 
1046     EnterCriticalSection( &path->cs );
1047 
1048     for (i = 0; i < path->num_namespaces; i++) heap_free( path->namespaces[i] );
1049     path->num_namespaces = 0;
1050     heap_free( path->namespaces );
1051     path->namespaces = NULL;
1052     heap_free( path->len_namespaces );
1053     path->len_namespaces = NULL;
1054 
1055     LeaveCriticalSection( &path->cs );
1056     return S_OK;
1057 }
1058 
1059 static HRESULT WINAPI path_GetScopeCount(
1060     IWbemPath *iface,
1061     ULONG *puCount)
1062 {
1063     FIXME("%p, %p\n", iface, puCount);
1064     return E_NOTIMPL;
1065 }
1066 
1067 static HRESULT WINAPI path_SetScope(
1068     IWbemPath *iface,
1069     ULONG uIndex,
1070     LPWSTR pszClass)
1071 {
1072     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszClass));
1073     return E_NOTIMPL;
1074 }
1075 
1076 static HRESULT WINAPI path_SetScopeFromText(
1077     IWbemPath *iface,
1078     ULONG uIndex,
1079     LPWSTR pszText)
1080 {
1081     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszText));
1082     return E_NOTIMPL;
1083 }
1084 
1085 static HRESULT WINAPI path_GetScope(
1086     IWbemPath *iface,
1087     ULONG uIndex,
1088     ULONG *puClassNameBufSize,
1089     LPWSTR pszClass,
1090     IWbemPathKeyList **pKeyList)
1091 {
1092     FIXME("%p, %u, %p, %p, %p\n", iface, uIndex, puClassNameBufSize, pszClass, pKeyList);
1093     return E_NOTIMPL;
1094 }
1095 
1096 static HRESULT WINAPI path_GetScopeAsText(
1097     IWbemPath *iface,
1098     ULONG uIndex,
1099     ULONG *puTextBufSize,
1100     LPWSTR pszText)
1101 {
1102     FIXME("%p, %u, %p, %p\n", iface, uIndex, puTextBufSize, pszText);
1103     return E_NOTIMPL;
1104 }
1105 
1106 static HRESULT WINAPI path_RemoveScope(
1107     IWbemPath *iface,
1108     ULONG uIndex)
1109 {
1110     FIXME("%p, %u\n", iface, uIndex);
1111     return E_NOTIMPL;
1112 }
1113 
1114 static HRESULT WINAPI path_RemoveAllScopes(
1115     IWbemPath *iface)
1116 {
1117     FIXME("%p\n", iface);
1118     return E_NOTIMPL;
1119 }
1120 
1121 static HRESULT WINAPI path_SetClassName(
1122     IWbemPath *iface,
1123     LPCWSTR name)
1124 {
1125     struct path *path = impl_from_IWbemPath( iface );
1126     WCHAR *class;
1127 
1128     TRACE("%p, %s\n", iface, debugstr_w(name));
1129 
1130     if (!name) return WBEM_E_INVALID_PARAMETER;
1131     if (!(class = strdupW( name ))) return WBEM_E_OUT_OF_MEMORY;
1132 
1133     EnterCriticalSection( &path->cs );
1134 
1135     heap_free( path->class );
1136     path->class = class;
1137     path->len_class = strlenW( path->class );
1138     path->flags |= WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
1139 
1140     LeaveCriticalSection( &path->cs );
1141     return S_OK;
1142 }
1143 
1144 static HRESULT WINAPI path_GetClassName(
1145     IWbemPath *iface,
1146     ULONG *len,
1147     LPWSTR name)
1148 {
1149     struct path *path = impl_from_IWbemPath( iface );
1150 
1151     TRACE("%p, %p, %p\n", iface, len, name);
1152 
1153     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
1154 
1155     EnterCriticalSection( &path->cs );
1156 
1157     if (!path->class)
1158     {
1159         LeaveCriticalSection( &path->cs );
1160         return WBEM_E_INVALID_OBJECT_PATH;
1161     }
1162     if (*len > path->len_class) strcpyW( name, path->class );
1163     *len = path->len_class + 1;
1164 
1165     LeaveCriticalSection( &path->cs );
1166     return S_OK;
1167 }
1168 
1169 static HRESULT WINAPI path_GetKeyList(
1170     IWbemPath *iface,
1171     IWbemPathKeyList **pOut)
1172 {
1173     struct path *path = impl_from_IWbemPath( iface );
1174     HRESULT hr;
1175 
1176     TRACE("%p, %p\n", iface, pOut);
1177 
1178     EnterCriticalSection( &path->cs );
1179 
1180     if (!path->class)
1181     {
1182         LeaveCriticalSection( &path->cs );
1183         return WBEM_E_INVALID_PARAMETER;
1184     }
1185     hr = WbemPathKeyList_create( iface, (void **)pOut );
1186 
1187     LeaveCriticalSection( &path->cs );
1188     return hr;
1189 }
1190 
1191 static HRESULT WINAPI path_CreateClassPart(
1192     IWbemPath *iface,
1193     LONG lFlags,
1194     LPCWSTR Name)
1195 {
1196     FIXME("%p, 0x%x, %s\n", iface, lFlags, debugstr_w(Name));
1197     return E_NOTIMPL;
1198 }
1199 
1200 static HRESULT WINAPI path_DeleteClassPart(
1201     IWbemPath *iface,
1202     LONG lFlags)
1203 {
1204     FIXME("%p, 0x%x\n", iface, lFlags);
1205     return E_NOTIMPL;
1206 }
1207 
1208 static BOOL WINAPI path_IsRelative(
1209     IWbemPath *iface,
1210     LPWSTR wszMachine,
1211     LPWSTR wszNamespace)
1212 {
1213     FIXME("%p, %s, %s\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace));
1214     return FALSE;
1215 }
1216 
1217 static BOOL WINAPI path_IsRelativeOrChild(
1218     IWbemPath *iface,
1219     LPWSTR wszMachine,
1220     LPWSTR wszNamespace,
1221     LONG lFlags)
1222 {
1223     FIXME("%p, %s, %s, 0x%x\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace), lFlags);
1224     return FALSE;
1225 }
1226 
1227 static BOOL WINAPI path_IsLocal(
1228     IWbemPath *iface,
1229     LPCWSTR wszMachine)
1230 {
1231     FIXME("%p, %s\n", iface, debugstr_w(wszMachine));
1232     return FALSE;
1233 }
1234 
1235 static BOOL WINAPI path_IsSameClassName(
1236     IWbemPath *iface,
1237     LPCWSTR wszClass)
1238 {
1239     FIXME("%p, %s\n", iface, debugstr_w(wszClass));
1240     return FALSE;
1241 }
1242 
1243 static const struct IWbemPathVtbl path_vtbl =
1244 {
1245     path_QueryInterface,
1246     path_AddRef,
1247     path_Release,
1248     path_SetText,
1249     path_GetText,
1250     path_GetInfo,
1251     path_SetServer,
1252     path_GetServer,
1253     path_GetNamespaceCount,
1254     path_SetNamespaceAt,
1255     path_GetNamespaceAt,
1256     path_RemoveNamespaceAt,
1257     path_RemoveAllNamespaces,
1258     path_GetScopeCount,
1259     path_SetScope,
1260     path_SetScopeFromText,
1261     path_GetScope,
1262     path_GetScopeAsText,
1263     path_RemoveScope,
1264     path_RemoveAllScopes,
1265     path_SetClassName,
1266     path_GetClassName,
1267     path_GetKeyList,
1268     path_CreateClassPart,
1269     path_DeleteClassPart,
1270     path_IsRelative,
1271     path_IsRelativeOrChild,
1272     path_IsLocal,
1273     path_IsSameClassName
1274 };
1275 
1276 HRESULT WbemPath_create( LPVOID *ppObj )
1277 {
1278     struct path *path;
1279 
1280     TRACE("%p\n", ppObj);
1281 
1282     if (!(path = heap_alloc( sizeof(*path) ))) return E_OUTOFMEMORY;
1283 
1284     path->IWbemPath_iface.lpVtbl = &path_vtbl;
1285     path->refs = 1;
1286     InitializeCriticalSection( &path->cs );
1287     path->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmiutils_path.cs");
1288     init_path( path );
1289 
1290     *ppObj = &path->IWbemPath_iface;
1291 
1292     TRACE("returning iface %p\n", *ppObj);
1293     return S_OK;
1294 }
1295