Release 1.5.29.
[wine] / dlls / wmiutils / path.c
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( IUnknown *pUnkOuter, IWbemPath *parent, LPVOID *ppObj )
280 {
281     struct keylist *keylist;
282
283     TRACE("%p, %p\n", pUnkOuter, 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     heap_free( path->text );
317     heap_free( path->server );
318     heap_free( path->namespaces );
319     heap_free( path->len_namespaces );
320     heap_free( path->class );
321     free_keys( path->keys, path->num_keys );
322     init_path( path );
323 }
324
325 static ULONG WINAPI path_AddRef(
326     IWbemPath *iface )
327 {
328     struct path *path = impl_from_IWbemPath( iface );
329     return InterlockedIncrement( &path->refs );
330 }
331
332 static ULONG WINAPI path_Release(
333     IWbemPath *iface )
334 {
335     struct path *path = impl_from_IWbemPath( iface );
336     LONG refs = InterlockedDecrement( &path->refs );
337     if (!refs)
338     {
339         TRACE("destroying %p\n", path);
340         clear_path( path );
341         path->cs.DebugInfo->Spare[0] = 0;
342         DeleteCriticalSection( &path->cs );
343         heap_free( path );
344     }
345     return refs;
346 }
347
348 static HRESULT WINAPI path_QueryInterface(
349     IWbemPath *iface,
350     REFIID riid,
351     void **ppvObject )
352 {
353     struct path *path = impl_from_IWbemPath( iface );
354
355     TRACE("%p, %s, %p\n", path, debugstr_guid( riid ), ppvObject );
356
357     if ( IsEqualGUID( riid, &IID_IWbemPath ) ||
358          IsEqualGUID( riid, &IID_IUnknown ) )
359     {
360         *ppvObject = iface;
361     }
362     else
363     {
364         FIXME("interface %s not implemented\n", debugstr_guid(riid));
365         return E_NOINTERFACE;
366     }
367     IWbemPath_AddRef( iface );
368     return S_OK;
369 }
370
371 static HRESULT parse_key( struct key *key, const WCHAR *str, unsigned int *ret_len )
372 {
373     const WCHAR *p, *q;
374     unsigned int len;
375
376     p = q = str;
377     while (*q && *q != '=')
378     {
379         if (*q == ',' || isspaceW( *q )) return WBEM_E_INVALID_PARAMETER;
380         q++;
381     }
382     len = q - p;
383     if (!(key->name = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
384     memcpy( key->name, p, len * sizeof(WCHAR) );
385     key->name[len] = 0;
386     key->len_name = len;
387
388     p = ++q;
389     if (!*p || *p == ',' || isspaceW( *p )) return WBEM_E_INVALID_PARAMETER;
390
391     while (*q && *q != ',') q++;
392     len = q - p;
393     if (!(key->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
394     memcpy( key->value, p, len * sizeof(WCHAR) );
395     key->value[len] = 0;
396     key->len_value = len;
397
398     *ret_len = q - str;
399     if (*q == ',') (*ret_len)++;
400     return S_OK;
401 }
402
403 static HRESULT parse_text( struct path *path, ULONG mode, const WCHAR *text )
404 {
405     HRESULT hr = E_OUTOFMEMORY;
406     const WCHAR *p, *q;
407     unsigned int i, len;
408
409     p = q = text;
410     if ((p[0] == '\\' && p[1] == '\\') || (p[0] == '/' && p[1] == '/'))
411     {
412         p += 2;
413         q = p;
414         while (*q && *q != '\\' && *q != '/') q++;
415         len = q - p;
416         if (!(path->server = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
417         memcpy( path->server, p, len * sizeof(WCHAR) );
418         path->server[len] = 0;
419         path->len_server = len;
420         path->flags |= WBEMPATH_INFO_PATH_HAD_SERVER;
421     }
422     p = q;
423     while (*q && *q != ':')
424     {
425         if (*q == '\\' || *q == '/') path->num_namespaces++;
426         q++;
427     }
428     if (path->num_namespaces)
429     {
430         if (!(path->namespaces = heap_alloc( path->num_namespaces * sizeof(WCHAR *) ))) goto done;
431         if (!(path->len_namespaces = heap_alloc( path->num_namespaces * sizeof(int) ))) goto done;
432
433         i = 0;
434         q = p;
435         while (*q && *q != ':')
436         {
437             if (*q == '\\' || *q == '/')
438             {
439                 p = q + 1;
440                 while (*p && *p != '\\' && *p != '/' && *p != ':') p++;
441                 len = p - q - 1;
442                 if (!(path->namespaces[i] = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
443                 memcpy( path->namespaces[i], q + 1, len * sizeof(WCHAR) );
444                 path->namespaces[i][len] = 0;
445                 path->len_namespaces[i] = len;
446                 i++;
447             }
448             q++;
449         }
450     }
451     if (*q == ':') q++;
452     p = q;
453     while (*q && *q != '.') q++;
454     len = q - p;
455     if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
456     memcpy( path->class, p, len * sizeof(WCHAR) );
457     path->class[len] = 0;
458     path->len_class = len;
459
460     if (*q == '.')
461     {
462         p = ++q;
463         path->num_keys++;
464         while (*q)
465         {
466             if (*q == ',') path->num_keys++;
467             q++;
468         }
469         if (!(path->keys = heap_alloc_zero( path->num_keys * sizeof(struct key) ))) goto done;
470         i = 0;
471         q = p;
472         while (*q)
473         {
474             if (i >= path->num_keys) break;
475             hr = parse_key( &path->keys[i], q, &len );
476             if (hr != S_OK) goto done;
477             q += len;
478             i++;
479         }
480     }
481     hr = S_OK;
482
483 done:
484     if (hr != S_OK) clear_path( path );
485     else path->flags |= WBEMPATH_INFO_CIM_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT;
486     return hr;
487 }
488
489 static HRESULT WINAPI path_SetText(
490     IWbemPath *iface,
491     ULONG uMode,
492     LPCWSTR pszPath)
493 {
494     struct path *path = impl_from_IWbemPath( iface );
495     HRESULT hr = S_OK;
496     int len;
497
498     TRACE("%p, %u, %s\n", iface, uMode, debugstr_w(pszPath));
499
500     if (!uMode || !pszPath) return WBEM_E_INVALID_PARAMETER;
501
502     EnterCriticalSection( &path->cs );
503
504     clear_path( path );
505     if (!pszPath[0]) goto done;
506     if ((hr = parse_text( path, uMode, pszPath )) != S_OK) goto done;
507
508     len = strlenW( pszPath );
509     if (!(path->text = heap_alloc( (len + 1) * sizeof(WCHAR) )))
510     {
511         clear_path( path );
512         hr = E_OUTOFMEMORY;
513         goto done;
514     }
515     strcpyW( path->text, pszPath );
516     path->len_text = len;
517
518 done:
519     LeaveCriticalSection( &path->cs );
520     return hr;
521 }
522
523 static WCHAR *build_namespace( struct path *path, int *len, BOOL leading_slash )
524 {
525     WCHAR *ret, *p;
526     int i;
527
528     *len = 0;
529     for (i = 0; i < path->num_namespaces; i++)
530     {
531         if (i > 0 || leading_slash) *len += 1;
532         *len += path->len_namespaces[i];
533     }
534     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
535     for (i = 0; i < path->num_namespaces; i++)
536     {
537         if (i > 0 || leading_slash) *p++ = '\\';
538         memcpy( p, path->namespaces[i], path->len_namespaces[i] * sizeof(WCHAR) );
539         p += path->len_namespaces[i];
540     }
541     *p = 0;
542     return ret;
543 }
544
545 static WCHAR *build_server( struct path *path, int *len )
546 {
547     WCHAR *ret, *p;
548
549     *len = 0;
550     if (path->len_server) *len += 2 + path->len_server;
551     else *len += 3;
552     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
553     if (path->len_server)
554     {
555         p[0] = p[1] = '\\';
556         strcpyW( p + 2, path->server );
557     }
558     else
559     {
560         p[0] = p[1] = '\\';
561         p[2] = '.';
562     }
563     return ret;
564 }
565
566 static WCHAR *build_keylist( struct path *path, int *len )
567 {
568     WCHAR *ret, *p;
569     unsigned int i;
570
571     *len = 0;
572     for (i = 0; i < path->num_keys; i++)
573     {
574         if (i > 0) *len += 1;
575         *len += path->keys[i].len_name + path->keys[i].len_value + 1;
576     }
577     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
578     for (i = 0; i < path->num_keys; i++)
579     {
580         if (i > 0) *p++ = ',';
581         memcpy( p, path->keys[i].name, path->keys[i].len_name * sizeof(WCHAR) );
582         p += path->keys[i].len_name;
583         *p++ = '=';
584         memcpy( p, path->keys[i].value, path->keys[i].len_value * sizeof(WCHAR) );
585         p += path->keys[i].len_value;
586     }
587     *p = 0;
588     return ret;
589 }
590
591 static WCHAR *build_path( struct path *path, LONG flags, int *len )
592 {
593     *len = 0;
594     switch (flags)
595     {
596     case 0:
597     {
598         int len_namespace, len_keylist;
599         WCHAR *ret, *namespace = build_namespace( path, &len_namespace, FALSE );
600         WCHAR *keylist = build_keylist( path, &len_keylist );
601
602         if (!namespace || !keylist)
603         {
604             heap_free( namespace );
605             heap_free( keylist );
606             return NULL;
607         }
608         *len = len_namespace;
609         if (path->len_class)
610         {
611             *len += path->len_class + 1;
612             if (path->num_keys) *len += len_keylist + 1;
613         }
614         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
615         {
616             heap_free( namespace );
617             heap_free( keylist );
618             return NULL;
619         }
620         strcpyW( ret, namespace );
621         if (path->len_class)
622         {
623             ret[len_namespace] = ':';
624             strcpyW( ret + len_namespace + 1, path->class );
625             if (path->num_keys)
626             {
627                 ret[len_namespace + path->len_class + 1] = '.';
628                 strcpyW( ret + len_namespace + path->len_class + 2, keylist );
629             }
630         }
631         heap_free( namespace );
632         heap_free( keylist );
633         return ret;
634
635     }
636     case WBEMPATH_GET_RELATIVE_ONLY:
637     {
638         int len_keylist;
639         WCHAR *ret, *keylist;
640
641         if (!path->len_class) return NULL;
642         if (!(keylist = build_keylist( path, &len_keylist ))) return NULL;
643
644         *len = path->len_class;
645         if (path->num_keys) *len += len_keylist + 1;
646         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
647         {
648             heap_free( keylist );
649             return NULL;
650         }
651         strcpyW( ret, path->class );
652         if (path->num_keys)
653         {
654             ret[path->len_class] = '.';
655             strcpyW( ret + path->len_class + 1, keylist );
656         }
657         heap_free( keylist );
658         return ret;
659     }
660     case WBEMPATH_GET_SERVER_TOO:
661     {
662         int len_namespace, len_server, len_keylist;
663         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
664         WCHAR *server = build_server( path, &len_server );
665         WCHAR *keylist = build_keylist( path, &len_keylist );
666
667         if (!namespace || !server || !keylist)
668         {
669             heap_free( namespace );
670             heap_free( server );
671             heap_free( keylist );
672             return NULL;
673         }
674         *len = len_namespace + len_server;
675         if (path->len_class)
676         {
677             *len += path->len_class + 1;
678             if (path->num_keys) *len += len_keylist + 1;
679         }
680         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
681         {
682             heap_free( namespace );
683             heap_free( server );
684             heap_free( keylist );
685             return NULL;
686         }
687         strcpyW( p, server );
688         p += len_server;
689         strcpyW( p, namespace );
690         p += len_namespace;
691         if (path->len_class)
692         {
693             *p++ = ':';
694             strcpyW( p, path->class );
695             if (path->num_keys)
696             {
697                 p[path->len_class] = '.';
698                 strcpyW( p + path->len_class + 1, keylist );
699             }
700         }
701         heap_free( namespace );
702         heap_free( server );
703         heap_free( keylist );
704         return ret;
705     }
706     case WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY:
707     {
708         int len_namespace, len_server;
709         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
710         WCHAR *server = build_server( path, &len_server );
711
712         if (!namespace || !server)
713         {
714             heap_free( namespace );
715             heap_free( server );
716             return NULL;
717         }
718         *len = len_namespace + len_server;
719         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
720         {
721             heap_free( namespace );
722             heap_free( server );
723             return NULL;
724         }
725         strcpyW( p, server );
726         p += len_server;
727         strcpyW( p, namespace );
728         heap_free( namespace );
729         heap_free( server );
730         return ret;
731     }
732     case WBEMPATH_GET_NAMESPACE_ONLY:
733         return build_namespace( path, len, FALSE );
734
735     case WBEMPATH_GET_ORIGINAL:
736         if (!path->len_text) return NULL;
737         *len = path->len_text;
738         return strdupW( path->text );
739
740     default:
741         ERR("unhandled flags 0x%x\n", flags);
742         return NULL;
743     }
744 }
745
746 static HRESULT WINAPI path_GetText(
747     IWbemPath *iface,
748     LONG lFlags,
749     ULONG *puBufferLength,
750     LPWSTR pszText)
751 {
752     struct path *path = impl_from_IWbemPath( iface );
753     HRESULT hr = S_OK;
754     WCHAR *str;
755     int len;
756
757     TRACE("%p, 0x%x, %p, %p\n", iface, lFlags, puBufferLength, pszText);
758
759     if (!puBufferLength) return WBEM_E_INVALID_PARAMETER;
760
761     EnterCriticalSection( &path->cs );
762
763     str = build_path( path, lFlags, &len );
764     if (*puBufferLength < len + 1)
765     {
766         *puBufferLength = len + 1;
767         goto done;
768     }
769     if (!pszText)
770     {
771         hr = WBEM_E_INVALID_PARAMETER;
772         goto done;
773     }
774     if (str) strcpyW( pszText, str );
775     else pszText[0] = 0;
776     *puBufferLength = len + 1;
777
778     TRACE("returning %s\n", debugstr_w(pszText));
779
780 done:
781     heap_free( str );
782     LeaveCriticalSection( &path->cs );
783     return hr;
784 }
785
786 static HRESULT WINAPI path_GetInfo(
787     IWbemPath *iface,
788     ULONG info,
789     ULONGLONG *response)
790 {
791     struct path *path = impl_from_IWbemPath( iface );
792
793     TRACE("%p, %u, %p\n", iface, info, response);
794
795     if (info || !response) return WBEM_E_INVALID_PARAMETER;
796
797     FIXME("some flags are not implemented\n");
798
799     EnterCriticalSection( &path->cs );
800
801     *response = path->flags;
802     if (!path->server || (path->len_server == 1 && path->server[0] == '.'))
803         *response |= WBEMPATH_INFO_ANON_LOCAL_MACHINE;
804     else
805         *response |= WBEMPATH_INFO_HAS_MACHINE_NAME;
806
807     if (!path->class)
808         *response |= WBEMPATH_INFO_SERVER_NAMESPACE_ONLY;
809     else
810     {
811         *response |= WBEMPATH_INFO_HAS_SUBSCOPES;
812         if (path->num_keys)
813             *response |= WBEMPATH_INFO_IS_INST_REF;
814         else
815             *response |= WBEMPATH_INFO_IS_CLASS_REF;
816     }
817
818     LeaveCriticalSection( &path->cs );
819     return S_OK;
820 }
821
822 static HRESULT WINAPI path_SetServer(
823     IWbemPath *iface,
824     LPCWSTR name)
825 {
826     struct path *path = impl_from_IWbemPath( iface );
827     static const ULONGLONG flags =
828         WBEMPATH_INFO_PATH_HAD_SERVER | WBEMPATH_INFO_V1_COMPLIANT |
829         WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
830     WCHAR *server;
831
832     TRACE("%p, %s\n", iface, debugstr_w(name));
833
834     EnterCriticalSection( &path->cs );
835
836     if (name)
837     {
838         if (!(server = strdupW( name )))
839         {
840             LeaveCriticalSection( &path->cs );
841             return WBEM_E_OUT_OF_MEMORY;
842         }
843         heap_free( path->server );
844         path->server = server;
845         path->len_server = strlenW( path->server );
846         path->flags |= flags;
847     }
848     else
849     {
850         heap_free( path->server );
851         path->server = NULL;
852         path->len_server = 0;
853         path->flags &= ~flags;
854     }
855
856     LeaveCriticalSection( &path->cs );
857     return S_OK;
858 }
859
860 static HRESULT WINAPI path_GetServer(
861     IWbemPath *iface,
862     ULONG *len,
863     LPWSTR name)
864 {
865     struct path *path = impl_from_IWbemPath( iface );
866
867     TRACE("%p, %p, %p\n", iface, len, name);
868
869     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
870
871     EnterCriticalSection( &path->cs );
872
873     if (!path->server)
874     {
875         LeaveCriticalSection( &path->cs );
876         return WBEM_E_NOT_AVAILABLE;
877     }
878     if (*len > path->len_server) strcpyW( name, path->server );
879     *len = path->len_server + 1;
880
881     LeaveCriticalSection( &path->cs );
882     return S_OK;
883 }
884
885 static HRESULT WINAPI path_GetNamespaceCount(
886     IWbemPath *iface,
887     ULONG *puCount)
888 {
889     struct path *path = impl_from_IWbemPath( iface );
890
891     TRACE("%p, %p\n", iface, puCount);
892
893     if (!puCount) return WBEM_E_INVALID_PARAMETER;
894
895     EnterCriticalSection( &path->cs );
896     *puCount = path->num_namespaces;
897     LeaveCriticalSection( &path->cs );
898     return S_OK;
899 }
900
901 static HRESULT WINAPI path_SetNamespaceAt(
902     IWbemPath *iface,
903     ULONG idx,
904     LPCWSTR name)
905 {
906     struct path *path = impl_from_IWbemPath( iface );
907     static const ULONGLONG flags =
908         WBEMPATH_INFO_V1_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT |
909         WBEMPATH_INFO_CIM_COMPLIANT;
910     int i, *tmp_len;
911     WCHAR **tmp, *new;
912     DWORD size;
913
914     TRACE("%p, %u, %s\n", iface, idx, debugstr_w(name));
915
916     EnterCriticalSection( &path->cs );
917
918     if (idx > path->num_namespaces || !name)
919     {
920         LeaveCriticalSection( &path->cs );
921         return WBEM_E_INVALID_PARAMETER;
922     }
923     if (!(new = strdupW( name )))
924     {
925         LeaveCriticalSection( &path->cs );
926         return WBEM_E_OUT_OF_MEMORY;
927     }
928     size = (path->num_namespaces + 1) * sizeof(WCHAR *);
929     if (path->namespaces) tmp = heap_realloc( path->namespaces, size );
930     else tmp = heap_alloc( size );
931     if (!tmp)
932     {
933         heap_free( new );
934         LeaveCriticalSection( &path->cs );
935         return WBEM_E_OUT_OF_MEMORY;
936     }
937     path->namespaces = tmp;
938     size = (path->num_namespaces + 1) * sizeof(int);
939     if (path->len_namespaces) tmp_len = heap_realloc( path->len_namespaces, size );
940     else tmp_len = heap_alloc( size );
941     if (!tmp_len)
942     {
943         heap_free( new );
944         LeaveCriticalSection( &path->cs );
945         return WBEM_E_OUT_OF_MEMORY;
946     }
947     path->len_namespaces = tmp_len;
948     for (i = idx; i < path->num_namespaces; i++)
949     {
950         path->namespaces[i + 1] = path->namespaces[i];
951         path->len_namespaces[i + 1] = path->len_namespaces[i];
952     }
953     path->namespaces[idx] = new;
954     path->len_namespaces[idx] = strlenW( new );
955     path->num_namespaces++;
956     path->flags |= flags;
957
958     LeaveCriticalSection( &path->cs );
959     return S_OK;
960 }
961
962 static HRESULT WINAPI path_GetNamespaceAt(
963     IWbemPath *iface,
964     ULONG idx,
965     ULONG *len,
966     LPWSTR name)
967 {
968     struct path *path = impl_from_IWbemPath( iface );
969
970     TRACE("%p, %u, %p, %p\n", iface, idx, len, name);
971
972     EnterCriticalSection( &path->cs );
973
974     if (!len || (*len && !name) || idx >= path->num_namespaces)
975     {
976         LeaveCriticalSection( &path->cs );
977         return WBEM_E_INVALID_PARAMETER;
978     }
979     if (*len > path->len_namespaces[idx]) strcpyW( name, path->namespaces[idx] );
980     *len = path->len_namespaces[idx] + 1;
981
982     LeaveCriticalSection( &path->cs );
983     return S_OK;
984 }
985
986 static HRESULT WINAPI path_RemoveNamespaceAt(
987     IWbemPath *iface,
988     ULONG idx)
989 {
990     struct path *path = impl_from_IWbemPath( iface );
991
992     TRACE("%p, %u\n", iface, idx);
993
994     EnterCriticalSection( &path->cs );
995
996     if (idx >= path->num_namespaces)
997     {
998         LeaveCriticalSection( &path->cs );
999         return WBEM_E_INVALID_PARAMETER;
1000     }
1001     heap_free( path->namespaces[idx] );
1002     while (idx < path->num_namespaces - 1)
1003     {
1004         path->namespaces[idx] = path->namespaces[idx + 1];
1005         path->len_namespaces[idx] = path->len_namespaces[idx + 1];
1006         idx++;
1007     }
1008     path->num_namespaces--;
1009
1010     LeaveCriticalSection( &path->cs );
1011     return S_OK;
1012 }
1013
1014 static HRESULT WINAPI path_RemoveAllNamespaces(
1015     IWbemPath *iface)
1016 {
1017     struct path *path = impl_from_IWbemPath( iface );
1018     int i;
1019
1020     TRACE("%p\n", iface);
1021
1022     EnterCriticalSection( &path->cs );
1023
1024     for (i = 0; i < path->num_namespaces; i++) heap_free( path->namespaces[i] );
1025     path->num_namespaces = 0;
1026     heap_free( path->namespaces );
1027     path->namespaces = NULL;
1028     heap_free( path->len_namespaces );
1029     path->len_namespaces = NULL;
1030
1031     LeaveCriticalSection( &path->cs );
1032     return S_OK;
1033 }
1034
1035 static HRESULT WINAPI path_GetScopeCount(
1036     IWbemPath *iface,
1037     ULONG *puCount)
1038 {
1039     FIXME("%p, %p\n", iface, puCount);
1040     return E_NOTIMPL;
1041 }
1042
1043 static HRESULT WINAPI path_SetScope(
1044     IWbemPath *iface,
1045     ULONG uIndex,
1046     LPWSTR pszClass)
1047 {
1048     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszClass));
1049     return E_NOTIMPL;
1050 }
1051
1052 static HRESULT WINAPI path_SetScopeFromText(
1053     IWbemPath *iface,
1054     ULONG uIndex,
1055     LPWSTR pszText)
1056 {
1057     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszText));
1058     return E_NOTIMPL;
1059 }
1060
1061 static HRESULT WINAPI path_GetScope(
1062     IWbemPath *iface,
1063     ULONG uIndex,
1064     ULONG *puClassNameBufSize,
1065     LPWSTR pszClass,
1066     IWbemPathKeyList **pKeyList)
1067 {
1068     FIXME("%p, %u, %p, %p, %p\n", iface, uIndex, puClassNameBufSize, pszClass, pKeyList);
1069     return E_NOTIMPL;
1070 }
1071
1072 static HRESULT WINAPI path_GetScopeAsText(
1073     IWbemPath *iface,
1074     ULONG uIndex,
1075     ULONG *puTextBufSize,
1076     LPWSTR pszText)
1077 {
1078     FIXME("%p, %u, %p, %p\n", iface, uIndex, puTextBufSize, pszText);
1079     return E_NOTIMPL;
1080 }
1081
1082 static HRESULT WINAPI path_RemoveScope(
1083     IWbemPath *iface,
1084     ULONG uIndex)
1085 {
1086     FIXME("%p, %u\n", iface, uIndex);
1087     return E_NOTIMPL;
1088 }
1089
1090 static HRESULT WINAPI path_RemoveAllScopes(
1091     IWbemPath *iface)
1092 {
1093     FIXME("%p\n", iface);
1094     return E_NOTIMPL;
1095 }
1096
1097 static HRESULT WINAPI path_SetClassName(
1098     IWbemPath *iface,
1099     LPCWSTR name)
1100 {
1101     struct path *path = impl_from_IWbemPath( iface );
1102     WCHAR *class;
1103
1104     TRACE("%p, %s\n", iface, debugstr_w(name));
1105
1106     if (!name) return WBEM_E_INVALID_PARAMETER;
1107     if (!(class = strdupW( name ))) return WBEM_E_OUT_OF_MEMORY;
1108
1109     EnterCriticalSection( &path->cs );
1110
1111     heap_free( path->class );
1112     path->class = class;
1113     path->len_class = strlenW( path->class );
1114     path->flags |= WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
1115
1116     LeaveCriticalSection( &path->cs );
1117     return S_OK;
1118 }
1119
1120 static HRESULT WINAPI path_GetClassName(
1121     IWbemPath *iface,
1122     ULONG *len,
1123     LPWSTR name)
1124 {
1125     struct path *path = impl_from_IWbemPath( iface );
1126
1127     TRACE("%p, %p, %p\n", iface, len, name);
1128
1129     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
1130
1131     EnterCriticalSection( &path->cs );
1132
1133     if (!path->class)
1134     {
1135         LeaveCriticalSection( &path->cs );
1136         return WBEM_E_INVALID_OBJECT_PATH;
1137     }
1138     if (*len > path->len_class) strcpyW( name, path->class );
1139     *len = path->len_class + 1;
1140
1141     LeaveCriticalSection( &path->cs );
1142     return S_OK;
1143 }
1144
1145 static HRESULT WINAPI path_GetKeyList(
1146     IWbemPath *iface,
1147     IWbemPathKeyList **pOut)
1148 {
1149     struct path *path = impl_from_IWbemPath( iface );
1150     HRESULT hr;
1151
1152     TRACE("%p, %p\n", iface, pOut);
1153
1154     EnterCriticalSection( &path->cs );
1155
1156     if (!path->class)
1157     {
1158         LeaveCriticalSection( &path->cs );
1159         return WBEM_E_INVALID_PARAMETER;
1160     }
1161     hr = WbemPathKeyList_create( NULL, iface, (void **)pOut );
1162
1163     LeaveCriticalSection( &path->cs );
1164     return hr;
1165 }
1166
1167 static HRESULT WINAPI path_CreateClassPart(
1168     IWbemPath *iface,
1169     LONG lFlags,
1170     LPCWSTR Name)
1171 {
1172     FIXME("%p, 0x%x, %s\n", iface, lFlags, debugstr_w(Name));
1173     return E_NOTIMPL;
1174 }
1175
1176 static HRESULT WINAPI path_DeleteClassPart(
1177     IWbemPath *iface,
1178     LONG lFlags)
1179 {
1180     FIXME("%p, 0x%x\n", iface, lFlags);
1181     return E_NOTIMPL;
1182 }
1183
1184 static BOOL WINAPI path_IsRelative(
1185     IWbemPath *iface,
1186     LPWSTR wszMachine,
1187     LPWSTR wszNamespace)
1188 {
1189     FIXME("%p, %s, %s\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace));
1190     return E_NOTIMPL;
1191 }
1192
1193 static BOOL WINAPI path_IsRelativeOrChild(
1194     IWbemPath *iface,
1195     LPWSTR wszMachine,
1196     LPWSTR wszNamespace,
1197     LONG lFlags)
1198 {
1199     FIXME("%p, %s, %s, 0x%x\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace), lFlags);
1200     return E_NOTIMPL;
1201 }
1202
1203 static BOOL WINAPI path_IsLocal(
1204     IWbemPath *iface,
1205     LPCWSTR wszMachine)
1206 {
1207     FIXME("%p, %s\n", iface, debugstr_w(wszMachine));
1208     return E_NOTIMPL;
1209 }
1210
1211 static BOOL WINAPI path_IsSameClassName(
1212     IWbemPath *iface,
1213     LPCWSTR wszClass)
1214 {
1215     FIXME("%p, %s\n", iface, debugstr_w(wszClass));
1216     return E_NOTIMPL;
1217 }
1218
1219 static const struct IWbemPathVtbl path_vtbl =
1220 {
1221     path_QueryInterface,
1222     path_AddRef,
1223     path_Release,
1224     path_SetText,
1225     path_GetText,
1226     path_GetInfo,
1227     path_SetServer,
1228     path_GetServer,
1229     path_GetNamespaceCount,
1230     path_SetNamespaceAt,
1231     path_GetNamespaceAt,
1232     path_RemoveNamespaceAt,
1233     path_RemoveAllNamespaces,
1234     path_GetScopeCount,
1235     path_SetScope,
1236     path_SetScopeFromText,
1237     path_GetScope,
1238     path_GetScopeAsText,
1239     path_RemoveScope,
1240     path_RemoveAllScopes,
1241     path_SetClassName,
1242     path_GetClassName,
1243     path_GetKeyList,
1244     path_CreateClassPart,
1245     path_DeleteClassPart,
1246     path_IsRelative,
1247     path_IsRelativeOrChild,
1248     path_IsLocal,
1249     path_IsSameClassName
1250 };
1251
1252 HRESULT WbemPath_create( IUnknown *pUnkOuter, LPVOID *ppObj )
1253 {
1254     struct path *path;
1255
1256     TRACE("%p, %p\n", pUnkOuter, ppObj);
1257
1258     if (!(path = heap_alloc( sizeof(*path) ))) return E_OUTOFMEMORY;
1259
1260     path->IWbemPath_iface.lpVtbl = &path_vtbl;
1261     path->refs = 1;
1262     InitializeCriticalSection( &path->cs );
1263     path->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmiutils_path.cs");
1264     init_path( path );
1265
1266     *ppObj = &path->IWbemPath_iface;
1267
1268     TRACE("returning iface %p\n", *ppObj);
1269     return S_OK;
1270 }