gdi32: Avoid creating a family object just to retrieve the font data.
[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 path
36 {
37     IWbemPath IWbemPath_iface;
38     LONG    refs;
39     WCHAR  *text;
40     int     len_text;
41     WCHAR  *server;
42     int     len_server;
43     WCHAR **namespaces;
44     int    *len_namespaces;
45     int     num_namespaces;
46     WCHAR  *class;
47     int     len_class;
48 };
49
50 static void init_path( struct path *path )
51 {
52     path->text           = NULL;
53     path->len_text       = 0;
54     path->server         = NULL;
55     path->len_server     = 0;
56     path->namespaces     = NULL;
57     path->len_namespaces = NULL;
58     path->num_namespaces = 0;
59     path->class          = NULL;
60     path->len_class      = 0;
61 }
62
63 static void clear_path( struct path *path )
64 {
65     heap_free( path->text );
66     heap_free( path->server );
67     heap_free( path->namespaces );
68     heap_free( path->len_namespaces );
69     heap_free( path->class );
70     init_path( path );
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 path_AddRef(
79     IWbemPath *iface )
80 {
81     struct path *path = impl_from_IWbemPath( iface );
82     return InterlockedIncrement( &path->refs );
83 }
84
85 static ULONG WINAPI path_Release(
86     IWbemPath *iface )
87 {
88     struct path *path = impl_from_IWbemPath( iface );
89     LONG refs = InterlockedDecrement( &path->refs );
90     if (!refs)
91     {
92         TRACE("destroying %p\n", path);
93         clear_path( path );
94         heap_free( path );
95     }
96     return refs;
97 }
98
99 static HRESULT WINAPI path_QueryInterface(
100     IWbemPath *iface,
101     REFIID riid,
102     void **ppvObject )
103 {
104     struct path *path = impl_from_IWbemPath( iface );
105
106     TRACE("%p, %s, %p\n", path, debugstr_guid( riid ), ppvObject );
107
108     if ( IsEqualGUID( riid, &IID_IWbemPath ) ||
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     IWbemPath_AddRef( iface );
119     return S_OK;
120 }
121
122 static HRESULT parse_text( struct path *path, ULONG mode, const WCHAR *text )
123 {
124     HRESULT hr = E_OUTOFMEMORY;
125     const WCHAR *p, *q;
126     unsigned int i, len;
127
128     p = q = text;
129     if ((p[0] == '\\' && p[1] == '\\') || (p[0] == '/' && p[1] == '/'))
130     {
131         p += 2;
132         q = p;
133         while (*q && *q != '\\' && *q != '/') q++;
134         len = q - p;
135         if (!(path->server = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
136         memcpy( path->server, p, len * sizeof(WCHAR) );
137         path->server[len] = 0;
138         path->len_server = len;
139     }
140     p = q;
141     while (*q && *q != ':')
142     {
143         if (*q == '\\' || *q == '/') path->num_namespaces++;
144         q++;
145     }
146     if (path->num_namespaces)
147     {
148         if (!(path->namespaces = heap_alloc( path->num_namespaces * sizeof(WCHAR *) ))) goto done;
149         if (!(path->len_namespaces = heap_alloc( path->num_namespaces * sizeof(int) ))) goto done;
150
151         i = 0;
152         q = p;
153         while (*q && *q != ':')
154         {
155             if (*q == '\\' || *q == '/')
156             {
157                 p = q + 1;
158                 while (*p && *p != '\\' && *p != '/' && *p != ':') p++;
159                 len = p - q - 1;
160                 if (!(path->namespaces[i] = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
161                 memcpy( path->namespaces[i], q + 1, len * sizeof(WCHAR) );
162                 path->namespaces[i][len] = 0;
163                 path->len_namespaces[i] = len;
164                 i++;
165             }
166             q++;
167         }
168     }
169     if (*q == ':') q++;
170     p = q;
171     while (*q && *q != '.') q++;
172     len = q - p;
173     if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
174     memcpy( path->class, p, len * sizeof(WCHAR) );
175     path->class[len] = 0;
176     path->len_class = len;
177
178     if (*q == '.') FIXME("handle key list\n");
179     hr = S_OK;
180
181 done:
182     if (hr != S_OK) clear_path( path );
183     return hr;
184 }
185
186 static HRESULT WINAPI path_SetText(
187     IWbemPath *iface,
188     ULONG uMode,
189     LPCWSTR pszPath)
190 {
191     struct path *path = impl_from_IWbemPath( iface );
192     HRESULT hr;
193     int len;
194
195     TRACE("%p, %u, %s\n", iface, uMode, debugstr_w(pszPath));
196
197     if (!uMode || !pszPath) return WBEM_E_INVALID_PARAMETER;
198
199     clear_path( path );
200     if ((hr = parse_text( path, uMode, pszPath )) != S_OK) return hr;
201
202     len = strlenW( pszPath );
203     if (!(path->text = heap_alloc( (len + 1) * sizeof(WCHAR) )))
204     {
205         clear_path( path );
206         return E_OUTOFMEMORY;
207     }
208     strcpyW( path->text, pszPath );
209     path->len_text = len;
210     return S_OK;
211 }
212
213 static WCHAR *build_namespace( struct path *path, int *len, BOOL leading_slash )
214 {
215     WCHAR *ret, *p;
216     int i;
217
218     *len = 0;
219     for (i = 0; i < path->num_namespaces; i++)
220     {
221         if (i > 0 || leading_slash) *len += 1;
222         *len += path->len_namespaces[i];
223     }
224     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
225     for (i = 0; i < path->num_namespaces; i++)
226     {
227         if (i > 0 || leading_slash) *p++ = '\\';
228         memcpy( p, path->namespaces[i], path->len_namespaces[i] * sizeof(WCHAR) );
229         p += path->len_namespaces[i];
230     }
231     *p = 0;
232     return ret;
233 }
234
235 static WCHAR *build_server( struct path *path, int *len )
236 {
237     WCHAR *ret, *p;
238
239     *len = 0;
240     if (path->len_server) *len += 2 + path->len_server;
241     else *len += 3;
242     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
243     if (path->len_server)
244     {
245         p[0] = p[1] = '\\';
246         strcpyW( p + 2, path->server );
247     }
248     else
249     {
250         p[0] = p[1] = '\\';
251         p[2] = '.';
252     }
253     return ret;
254 }
255
256 static WCHAR *build_path( struct path *path, LONG flags, int *len )
257 {
258     switch (flags)
259     {
260     case 0:
261     {
262         int len_namespace;
263         WCHAR *ret, *namespace = build_namespace( path, &len_namespace, FALSE );
264
265         if (!namespace) return NULL;
266
267         *len = len_namespace;
268         if (path->len_class) *len += 1 + path->len_class;
269         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
270         {
271             heap_free( namespace );
272             return NULL;
273         }
274         strcpyW( ret, namespace );
275         if (path->len_class)
276         {
277             ret[len_namespace] = ':';
278             strcpyW( ret + len_namespace + 1, path->class );
279         }
280         heap_free( namespace );
281         return ret;
282
283     }
284     case WBEMPATH_GET_RELATIVE_ONLY:
285         if (!path->len_class)
286         {
287             *len = 0;
288             return NULL;
289         }
290         *len = path->len_class;
291         return strdupW( path->class );
292
293     case WBEMPATH_GET_SERVER_TOO:
294     {
295         int len_namespace, len_server;
296         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
297         WCHAR *server = build_server( path, &len_server );
298
299         if (!namespace || !server)
300         {
301             heap_free( namespace );
302             heap_free( server );
303             return NULL;
304         }
305         *len = len_namespace + len_server;
306         if (path->len_class) *len += 1 + path->len_class;
307         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
308         {
309             heap_free( namespace );
310             heap_free( server );
311             return NULL;
312         }
313         strcpyW( p, server );
314         p += len_server;
315         strcpyW( p, namespace );
316         p += len_namespace;
317         if (path->len_class)
318         {
319             *p = ':';
320             strcpyW( p + 1, path->class );
321         }
322         heap_free( namespace );
323         heap_free( server );
324         return ret;
325     }
326     case WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY:
327     {
328         int len_namespace, len_server;
329         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
330         WCHAR *server = build_server( path, &len_server );
331
332         if (!namespace || !server)
333         {
334             heap_free( namespace );
335             heap_free( server );
336             return NULL;
337         }
338         *len = len_namespace + len_server;
339         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
340         {
341             heap_free( namespace );
342             heap_free( server );
343             return NULL;
344         }
345         strcpyW( p, server );
346         p += len_server;
347         strcpyW( p, namespace );
348         heap_free( namespace );
349         heap_free( server );
350         return ret;
351     }
352     case WBEMPATH_GET_NAMESPACE_ONLY:
353         return build_namespace( path, len, FALSE );
354
355     case WBEMPATH_GET_ORIGINAL:
356         if (!path->len_text)
357         {
358             *len = 0;
359             return NULL;
360         }
361         *len = path->len_text;
362         return strdupW( path->text );
363
364     default:
365         ERR("unhandled flags 0x%x\n", flags);
366         return NULL;
367     }
368 }
369
370 static HRESULT WINAPI path_GetText(
371     IWbemPath *iface,
372     LONG lFlags,
373     ULONG *puBufferLength,
374     LPWSTR pszText)
375 {
376     struct path *path = impl_from_IWbemPath( iface );
377     WCHAR *str;
378     int len;
379
380     TRACE("%p, 0x%x, %p, %p\n", iface, lFlags, puBufferLength, pszText);
381
382     if (!puBufferLength) return WBEM_E_INVALID_PARAMETER;
383
384     str = build_path( path, lFlags, &len );
385
386     if (*puBufferLength < len + 1)
387     {
388         *puBufferLength = len + 1;
389         return S_OK;
390     }
391     if (!pszText)
392     {
393         heap_free( str );
394         return WBEM_E_INVALID_PARAMETER;
395     }
396     if (str) strcpyW( pszText, str );
397     else pszText[0] = 0;
398     *puBufferLength = len + 1;
399
400     TRACE("<-- %s\n", debugstr_w(pszText));
401     heap_free( str );
402     return S_OK;
403 }
404
405 static HRESULT WINAPI path_GetInfo(
406     IWbemPath *iface,
407     ULONG uRequestedInfo,
408     ULONGLONG *puResponse)
409 {
410     FIXME("%p, %d, %p\n", iface, uRequestedInfo, puResponse);
411     return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI path_SetServer(
415     IWbemPath *iface,
416     LPCWSTR Name)
417 {
418     FIXME("%p, %s\n", iface, debugstr_w(Name));
419     return E_NOTIMPL;
420 }
421
422 static HRESULT WINAPI path_GetServer(
423     IWbemPath *iface,
424     ULONG *len,
425     LPWSTR name)
426 {
427     struct path *path = impl_from_IWbemPath( iface );
428
429     TRACE("%p, %p, %p\n", iface, len, name);
430
431     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
432     if (!path->class) return WBEM_E_NOT_AVAILABLE;
433     if (*len > path->len_server) strcpyW( name, path->server );
434     *len = path->len_server + 1;
435     return S_OK;
436 }
437
438 static HRESULT WINAPI path_GetNamespaceCount(
439     IWbemPath *iface,
440     ULONG *puCount)
441 {
442     struct path *path = impl_from_IWbemPath( iface );
443
444     TRACE("%p, %p\n", iface, puCount);
445
446     if (!puCount) return WBEM_E_INVALID_PARAMETER;
447     *puCount = path->num_namespaces;
448     return S_OK;
449 }
450
451 static HRESULT WINAPI path_SetNamespaceAt(
452     IWbemPath *iface,
453     ULONG uIndex,
454     LPCWSTR pszName)
455 {
456     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszName));
457     return E_NOTIMPL;
458 }
459
460 static HRESULT WINAPI path_GetNamespaceAt(
461     IWbemPath *iface,
462     ULONG uIndex,
463     ULONG *puNameBufLength,
464     LPWSTR pName)
465 {
466     FIXME("%p, %u, %p, %p\n", iface, uIndex, puNameBufLength, pName);
467     return E_NOTIMPL;
468 }
469
470 static HRESULT WINAPI path_RemoveNamespaceAt(
471     IWbemPath *iface,
472     ULONG uIndex)
473 {
474     FIXME("%p, %u\n", iface, uIndex);
475     return E_NOTIMPL;
476 }
477
478 static HRESULT WINAPI path_RemoveAllNamespaces(
479         IWbemPath *iface)
480 {
481     FIXME("%p\n", iface);
482     return E_NOTIMPL;
483 }
484
485 static HRESULT WINAPI path_GetScopeCount(
486         IWbemPath *iface,
487         ULONG *puCount)
488 {
489     FIXME("%p, %p\n", iface, puCount);
490     return E_NOTIMPL;
491 }
492
493 static HRESULT WINAPI path_SetScope(
494     IWbemPath *iface,
495     ULONG uIndex,
496     LPWSTR pszClass)
497 {
498     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszClass));
499     return E_NOTIMPL;
500 }
501
502 static HRESULT WINAPI path_SetScopeFromText(
503     IWbemPath *iface,
504     ULONG uIndex,
505     LPWSTR pszText)
506 {
507     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszText));
508     return E_NOTIMPL;
509 }
510
511 static HRESULT WINAPI path_GetScope(
512     IWbemPath *iface,
513     ULONG uIndex,
514     ULONG *puClassNameBufSize,
515     LPWSTR pszClass,
516     IWbemPathKeyList **pKeyList)
517 {
518     FIXME("%p, %u, %p, %p, %p\n", iface, uIndex, puClassNameBufSize, pszClass, pKeyList);
519     return E_NOTIMPL;
520 }
521
522 static HRESULT WINAPI path_GetScopeAsText(
523     IWbemPath *iface,
524     ULONG uIndex,
525     ULONG *puTextBufSize,
526     LPWSTR pszText)
527 {
528     FIXME("%p, %u, %p, %p\n", iface, uIndex, puTextBufSize, pszText);
529     return E_NOTIMPL;
530 }
531
532 static HRESULT WINAPI path_RemoveScope(
533     IWbemPath *iface,
534     ULONG uIndex)
535 {
536     FIXME("%p, %u\n", iface, uIndex);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI path_RemoveAllScopes(
541     IWbemPath *iface)
542 {
543     FIXME("%p\n", iface);
544     return E_NOTIMPL;
545 }
546
547 static HRESULT WINAPI path_SetClassName(
548     IWbemPath *iface,
549     LPCWSTR Name)
550 {
551     FIXME("%p, %s\n", iface, debugstr_w(Name));
552     return E_NOTIMPL;
553 }
554
555 static HRESULT WINAPI path_GetClassName(
556     IWbemPath *iface,
557     ULONG *len,
558     LPWSTR name)
559 {
560     struct path *path = impl_from_IWbemPath( iface );
561
562     TRACE("%p, %p, %p\n", iface, len, name);
563
564     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
565     if (!path->class) return WBEM_E_INVALID_OBJECT_PATH;
566     if (*len > path->len_class) strcpyW( name, path->class );
567     *len = path->len_class + 1;
568     return S_OK;
569 }
570
571 static HRESULT WINAPI path_GetKeyList(
572     IWbemPath *iface,
573     IWbemPathKeyList **pOut)
574 {
575     FIXME("%p, %p\n", iface, pOut);
576     return E_NOTIMPL;
577 }
578
579 static HRESULT WINAPI path_CreateClassPart(
580     IWbemPath *iface,
581     LONG lFlags,
582     LPCWSTR Name)
583 {
584     FIXME("%p, 0x%x, %s\n", iface, lFlags, debugstr_w(Name));
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI path_DeleteClassPart(
589     IWbemPath *iface,
590     LONG lFlags)
591 {
592     FIXME("%p, 0x%x\n", iface, lFlags);
593     return E_NOTIMPL;
594 }
595
596 static BOOL WINAPI path_IsRelative(
597     IWbemPath *iface,
598     LPWSTR wszMachine,
599     LPWSTR wszNamespace)
600 {
601     FIXME("%p, %s, %s\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace));
602     return E_NOTIMPL;
603 }
604
605 static BOOL WINAPI path_IsRelativeOrChild(
606     IWbemPath *iface,
607     LPWSTR wszMachine,
608     LPWSTR wszNamespace,
609     LONG lFlags)
610 {
611     FIXME("%p, %s, %s, 0x%x\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace), lFlags);
612     return E_NOTIMPL;
613 }
614
615 static BOOL WINAPI path_IsLocal(
616     IWbemPath *iface,
617     LPCWSTR wszMachine)
618 {
619     FIXME("%p, %s\n", iface, debugstr_w(wszMachine));
620     return E_NOTIMPL;
621 }
622
623 static BOOL WINAPI path_IsSameClassName(
624     IWbemPath *iface,
625     LPCWSTR wszClass)
626 {
627     FIXME("%p, %s\n", iface, debugstr_w(wszClass));
628     return E_NOTIMPL;
629 }
630
631 static const struct IWbemPathVtbl path_vtbl =
632 {
633     path_QueryInterface,
634     path_AddRef,
635     path_Release,
636     path_SetText,
637     path_GetText,
638     path_GetInfo,
639     path_SetServer,
640     path_GetServer,
641     path_GetNamespaceCount,
642     path_SetNamespaceAt,
643     path_GetNamespaceAt,
644     path_RemoveNamespaceAt,
645     path_RemoveAllNamespaces,
646     path_GetScopeCount,
647     path_SetScope,
648     path_SetScopeFromText,
649     path_GetScope,
650     path_GetScopeAsText,
651     path_RemoveScope,
652     path_RemoveAllScopes,
653     path_SetClassName,
654     path_GetClassName,
655     path_GetKeyList,
656     path_CreateClassPart,
657     path_DeleteClassPart,
658     path_IsRelative,
659     path_IsRelativeOrChild,
660     path_IsLocal,
661     path_IsSameClassName
662 };
663
664 HRESULT WbemPath_create( IUnknown *pUnkOuter, LPVOID *ppObj )
665 {
666     struct path *path;
667
668     TRACE("%p, %p\n", pUnkOuter, ppObj);
669
670     if (!(path = heap_alloc( sizeof(*path) ))) return E_OUTOFMEMORY;
671
672     path->IWbemPath_iface.lpVtbl = &path_vtbl;
673     path->refs = 1;
674     init_path( path );
675
676     *ppObj = &path->IWbemPath_iface;
677
678     TRACE("returning iface %p\n", *ppObj);
679     return S_OK;
680 }