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