iphlpapi: Move the ICMP reply retrieval to a helper function.
[wine.git] / dlls / wbemprox / query.c
blob3d60825f24e9ad028f8bdbc325fc101c650d1995
1 /*
2 * Copyright 2012 Hans Leidekker for CodeWeavers
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.
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.
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
19 #define COBJMACROS
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wbemcli.h"
27 #include "wine/debug.h"
28 #include "wbemprox_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32 static HRESULT append_table( struct view *view, struct table *table )
34 struct table **tmp;
35 if (!(tmp = heap_realloc( view->table, (view->table_count + 1) * sizeof(*tmp) ))) return E_OUTOFMEMORY;
36 view->table = tmp;
37 view->table[view->table_count++] = table;
38 return S_OK;
41 HRESULT create_view( enum view_type type, const WCHAR *path, const struct keyword *keywordlist, const WCHAR *class,
42 const struct property *proplist, const struct expr *cond, struct view **ret )
44 struct view *view = heap_alloc_zero( sizeof(*view) );
46 if (!view) return E_OUTOFMEMORY;
48 switch (type)
50 case VIEW_TYPE_ASSOCIATORS:
51 view->path = path;
52 view->keywordlist = keywordlist;
53 break;
55 case VIEW_TYPE_SELECT:
57 struct table *table = grab_table( class );
58 HRESULT hr;
60 if (table && (hr = append_table( view, table )) != S_OK)
62 heap_free( view );
63 return hr;
65 view->proplist = proplist;
66 view->cond = cond;
67 break;
69 default:
70 ERR( "unhandled type %u\n", type );
71 heap_free( view );
72 return E_INVALIDARG;
75 view->type = type;
76 *ret = view;
77 return S_OK;
80 void destroy_view( struct view *view )
82 ULONG i;
83 if (!view) return;
84 for (i = 0; i < view->table_count; i++) release_table( view->table[i] );
85 heap_free( view->table );
86 heap_free( view->result );
87 heap_free( view );
90 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
92 const WCHAR *p = lstr, *q = rstr;
94 while (*p && *q)
96 if (*q == '%')
98 while (*q == '%') q++;
99 if (!*q) return TRUE;
100 while (*p && *q && towupper( *p ) == towupper( *q )) { p++; q++; };
101 if (!*p && !*q) return TRUE;
103 if (*q != '%' && towupper( *p++ ) != towupper( *q++ )) return FALSE;
105 return TRUE;
108 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
110 if (!lstr || !rstr)
112 *val = 0;
113 return S_OK;
115 switch (op)
117 case OP_EQ:
118 *val = !wcscmp( lstr, rstr );
119 break;
120 case OP_GT:
121 *val = wcscmp( lstr, rstr ) > 0;
122 break;
123 case OP_LT:
124 *val = wcscmp( lstr, rstr ) < 0;
125 break;
126 case OP_LE:
127 *val = wcscmp( lstr, rstr ) <= 0;
128 break;
129 case OP_GE:
130 *val = wcscmp( lstr, rstr ) >= 0;
131 break;
132 case OP_NE:
133 *val = wcscmp( lstr, rstr );
134 break;
135 case OP_LIKE:
136 *val = eval_like( lstr, rstr );
137 break;
138 default:
139 ERR("unhandled operator %u\n", op);
140 return WBEM_E_INVALID_QUERY;
142 return S_OK;
145 static BOOL is_int( CIMTYPE type )
147 switch (type)
149 case CIM_SINT8:
150 case CIM_SINT16:
151 case CIM_SINT32:
152 case CIM_SINT64:
153 case CIM_UINT8:
154 case CIM_UINT16:
155 case CIM_UINT32:
156 case CIM_UINT64:
157 return TRUE;
158 default:
159 return FALSE;
163 static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
165 if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL &&
166 expr->right->type == EXPR_SVAL) return TRUE;
167 else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL &&
168 expr->left->type == EXPR_SVAL) return TRUE;
169 return FALSE;
172 static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
174 if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL &&
175 (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE;
176 else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL &&
177 (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE;
178 return FALSE;
181 static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val )
183 if (ltype == CIM_STRING) lval = !wcsicmp( (const WCHAR *)(INT_PTR)lval, L"True" ) ? -1 : 0;
184 else if (rtype == CIM_STRING) rval = !wcsicmp( (const WCHAR *)(INT_PTR)rval, L"True" ) ? -1 : 0;
186 switch (op)
188 case OP_EQ:
189 *val = (lval == rval);
190 break;
191 case OP_NE:
192 *val = (lval != rval);
193 break;
194 default:
195 ERR("unhandled operator %u\n", op);
196 return WBEM_E_INVALID_QUERY;
198 return S_OK;
201 static inline BOOL is_refcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
203 if (ltype == CIM_REFERENCE && expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) return TRUE;
204 else if (rtype == CIM_REFERENCE && expr->right->type == EXPR_PROPVAL && expr->left->type == EXPR_SVAL) return TRUE;
205 return FALSE;
208 static HRESULT eval_refcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
210 if (!lstr || !rstr)
212 *val = 0;
213 return S_OK;
215 switch (op)
217 case OP_EQ:
218 *val = !wcsicmp( lstr, rstr );
219 break;
220 case OP_NE:
221 *val = wcsicmp( lstr, rstr );
222 break;
223 default:
224 ERR("unhandled operator %u\n", op);
225 return WBEM_E_INVALID_QUERY;
227 return S_OK;
230 static UINT resolve_type( UINT left, UINT right )
232 switch (left)
234 case CIM_SINT8:
235 case CIM_SINT16:
236 case CIM_SINT32:
237 case CIM_SINT64:
238 case CIM_UINT8:
239 case CIM_UINT16:
240 case CIM_UINT32:
241 case CIM_UINT64:
242 switch (right)
244 case CIM_SINT8:
245 case CIM_SINT16:
246 case CIM_SINT32:
247 case CIM_SINT64:
248 case CIM_UINT8:
249 case CIM_UINT16:
250 case CIM_UINT32:
251 case CIM_UINT64:
252 return CIM_UINT64;
253 default: break;
255 break;
257 case CIM_STRING:
258 if (right == CIM_STRING) return CIM_STRING;
259 break;
261 case CIM_BOOLEAN:
262 if (right == CIM_BOOLEAN) return CIM_BOOLEAN;
263 break;
265 case CIM_REFERENCE:
266 if (right == CIM_REFERENCE) return CIM_REFERENCE;
267 break;
269 default:
270 break;
272 return CIM_ILLEGAL;
275 static const WCHAR *format_int( WCHAR *buf, UINT len, CIMTYPE type, LONGLONG val )
277 switch (type)
279 case CIM_SINT8:
280 case CIM_SINT16:
281 case CIM_SINT32:
282 swprintf( buf, len, L"%d", val );
283 return buf;
285 case CIM_UINT8:
286 case CIM_UINT16:
287 case CIM_UINT32:
288 swprintf( buf, len, L"%u", val );
289 return buf;
291 case CIM_SINT64:
292 wsprintfW( buf, L"%I64d", val );
293 return buf;
295 case CIM_UINT64:
296 wsprintfW( buf, L"%I64u", val );
297 return buf;
299 default:
300 ERR( "unhandled type %u\n", type );
301 return NULL;
305 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
306 LONGLONG *val, UINT *type )
308 HRESULT lret, rret;
309 LONGLONG lval, rval;
310 UINT ltype, rtype;
312 lret = eval_cond( table, row, expr->left, &lval, &ltype );
313 rret = eval_cond( table, row, expr->right, &rval, &rtype );
314 if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
316 *type = resolve_type( ltype, rtype );
318 if (is_strcmp( expr, ltype, rtype ))
320 const WCHAR *lstr, *rstr;
321 WCHAR lbuf[21], rbuf[21];
323 if (is_int( ltype )) lstr = format_int( lbuf, ARRAY_SIZE( lbuf ), ltype, lval );
324 else lstr = (const WCHAR *)(INT_PTR)lval;
326 if (is_int( rtype )) rstr = format_int( rbuf, ARRAY_SIZE( rbuf ), rtype, rval );
327 else rstr = (const WCHAR *)(INT_PTR)rval;
329 return eval_strcmp( expr->op, lstr, rstr, val );
331 if (is_boolcmp( expr, ltype, rtype ))
333 return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val );
335 if (is_refcmp( expr, ltype, rtype ))
337 return eval_refcmp( expr->op, (const WCHAR *)(INT_PTR)lval, (const WCHAR *)(INT_PTR)rval, val );
340 switch (expr->op)
342 case OP_EQ:
343 *val = (lval == rval);
344 break;
345 case OP_AND:
346 *val = (lval && rval);
347 break;
348 case OP_OR:
349 *val = (lval || rval);
350 break;
351 case OP_GT:
352 *val = (lval > rval);
353 break;
354 case OP_LT:
355 *val = (lval < rval);
356 break;
357 case OP_LE:
358 *val = (lval <= rval);
359 break;
360 case OP_GE:
361 *val = (lval >= rval);
362 break;
363 case OP_NE:
364 *val = (lval != rval);
365 break;
366 default:
367 ERR("unhandled operator %u\n", expr->op);
368 return WBEM_E_INVALID_QUERY;
370 return S_OK;
373 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
374 LONGLONG *val, UINT *type )
377 HRESULT hr;
378 UINT column;
379 LONGLONG lval;
381 if (expr->op == OP_NOT)
383 hr = eval_cond( table, row, expr->left, &lval, type );
384 if (hr != S_OK)
385 return hr;
386 *val = !lval;
387 return S_OK;
390 hr = get_column_index( table, expr->left->u.propval->name, &column );
391 if (hr != S_OK)
392 return hr;
394 hr = get_value( table, row, column, &lval );
395 if (hr != S_OK)
396 return hr;
398 switch (expr->op)
400 case OP_ISNULL:
401 *val = !lval;
402 break;
403 case OP_NOTNULL:
404 *val = lval;
405 break;
406 default:
407 ERR("unknown operator %u\n", expr->op);
408 return WBEM_E_INVALID_QUERY;
411 *type = table->columns[column].type & CIM_TYPE_MASK;
412 return S_OK;
415 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
416 LONGLONG *val, UINT *type )
419 HRESULT hr;
420 UINT column;
422 hr = get_column_index( table, propval->name, &column );
423 if (hr != S_OK)
424 return hr;
426 *type = table->columns[column].type & CIM_TYPE_MASK;
427 return get_value( table, row, column, val );
430 HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type )
432 if (!cond)
434 *val = 1;
435 *type = CIM_UINT64;
436 return S_OK;
438 switch (cond->type)
440 case EXPR_COMPLEX:
441 return eval_binary( table, row, &cond->u.expr, val, type );
443 case EXPR_UNARY:
444 return eval_unary( table, row, &cond->u.expr, val, type );
446 case EXPR_PROPVAL:
447 return eval_propval( table, row, cond->u.propval, val, type );
449 case EXPR_SVAL:
450 *val = (INT_PTR)cond->u.sval;
451 *type = CIM_STRING;
452 return S_OK;
454 case EXPR_IVAL:
455 *val = cond->u.ival;
456 *type = CIM_UINT64;
457 return S_OK;
459 case EXPR_BVAL:
460 *val = cond->u.ival;
461 *type = CIM_BOOLEAN;
462 return S_OK;
464 default:
465 ERR("invalid expression type\n");
466 break;
468 return WBEM_E_INVALID_QUERY;
471 static WCHAR *build_assoc_query( const WCHAR *class, UINT class_len )
473 static const WCHAR fmtW[] = L"SELECT * FROM __ASSOCIATORS WHERE Class='%s'";
474 UINT len = class_len + ARRAY_SIZE(fmtW);
475 WCHAR *ret;
477 if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
478 swprintf( ret, len, fmtW, class );
479 return ret;
482 static HRESULT create_assoc_enum( const WCHAR *class, UINT class_len, IEnumWbemClassObject **iter )
484 WCHAR *query;
485 HRESULT hr;
487 if (!(query = build_assoc_query( class, class_len ))) return E_OUTOFMEMORY;
488 hr = exec_query( query, iter );
489 heap_free( query );
490 return hr;
493 static WCHAR *build_antecedent_query( const WCHAR *assocclass, const WCHAR *dependent )
495 static const WCHAR fmtW[] = L"SELECT Antecedent FROM %s WHERE Dependent='%s'";
496 UINT len = lstrlenW(assocclass) + lstrlenW(dependent) + ARRAY_SIZE(fmtW);
497 WCHAR *ret;
499 if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
500 swprintf( ret, len, fmtW, assocclass, dependent );
501 return ret;
504 static BSTR build_servername(void)
506 WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
507 DWORD len = ARRAY_SIZE( server );
509 if (!(GetComputerNameW( server, &len ))) return NULL;
510 for (p = server; *p; p++) *p = towupper( *p );
511 return SysAllocString( server );
514 static BSTR build_namespace(void)
516 return SysAllocString( L"ROOT\\CIMV2" );
519 static WCHAR *build_canonical_path( const WCHAR *relpath )
521 BSTR server, namespace;
522 WCHAR *ret;
523 UINT len, i;
525 if (!(server = build_servername())) return NULL;
526 if (!(namespace = build_namespace()))
528 SysFreeString( server );
529 return NULL;
532 len = ARRAY_SIZE( L"\\\\%s\\%s:" ) + SysStringLen( server ) + SysStringLen( namespace ) + lstrlenW( relpath );
533 if ((ret = heap_alloc( len * sizeof(WCHAR ) )))
535 len = swprintf( ret, len, L"\\\\%s\\%s:", server, namespace );
536 for (i = 0; i < lstrlenW( relpath ); i ++)
538 if (relpath[i] == '\'') ret[len++] = '"';
539 else ret[len++] = relpath[i];
541 ret[len] = 0;
544 SysFreeString( server );
545 SysFreeString( namespace );
546 return ret;
549 static HRESULT get_antecedent( const WCHAR *assocclass, const WCHAR *dependent, BSTR *ret )
551 WCHAR *fullpath, *str;
552 IEnumWbemClassObject *iter = NULL;
553 IWbemClassObject *obj;
554 HRESULT hr = E_OUTOFMEMORY;
555 ULONG count;
556 VARIANT var;
558 if (!(fullpath = build_canonical_path( dependent ))) return E_OUTOFMEMORY;
559 if (!(str = build_antecedent_query( assocclass, fullpath ))) goto done;
560 if ((hr = exec_query( str, &iter )) != S_OK) goto done;
562 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
563 if (!count)
565 *ret = NULL;
566 goto done;
569 hr = IWbemClassObject_Get( obj, L"Antecedent", 0, &var, NULL, NULL );
570 IWbemClassObject_Release( obj );
571 if (hr != S_OK) goto done;
572 *ret = V_BSTR( &var );
574 done:
575 if (iter) IEnumWbemClassObject_Release( iter );
576 heap_free( str );
577 heap_free( fullpath );
578 return hr;
581 static HRESULT do_query( const WCHAR *str, struct query **ret_query )
583 struct query *query;
584 HRESULT hr;
586 if (!(query = create_query())) return E_OUTOFMEMORY;
587 if ((hr = parse_query( str, &query->view, &query->mem )) != S_OK || (hr = execute_view( query->view )) != S_OK)
589 release_query( query );
590 return hr;
592 *ret_query = query;
593 return S_OK;
596 static HRESULT get_antecedent_table( const WCHAR *assocclass, const WCHAR *dependent, struct table **table )
598 BSTR antecedent = NULL;
599 struct path *path = NULL;
600 WCHAR *str = NULL;
601 struct query *query = NULL;
602 HRESULT hr;
604 if ((hr = get_antecedent( assocclass, dependent, &antecedent )) != S_OK) return hr;
605 if (!antecedent)
607 *table = NULL;
608 return S_OK;
610 if ((hr = parse_path( antecedent, &path )) != S_OK) goto done;
611 if (!(str = query_from_path( path )))
613 hr = E_OUTOFMEMORY;
614 goto done;
617 if ((hr = do_query( str, &query )) != S_OK) goto done;
618 if (query->view->table_count) *table = addref_table( query->view->table[0] );
619 else *table = NULL;
621 done:
622 if (query) release_query( query );
623 free_path( path );
624 SysFreeString( antecedent );
625 heap_free( str );
626 return hr;
629 static HRESULT exec_assoc_view( struct view *view )
631 IEnumWbemClassObject *iter = NULL;
632 struct path *path;
633 HRESULT hr;
635 if (view->keywordlist) FIXME( "ignoring keywords\n" );
636 if ((hr = parse_path( view->path, &path )) != S_OK) return hr;
638 if ((hr = create_assoc_enum( path->class, path->class_len, &iter )) != S_OK) goto done;
639 for (;;)
641 ULONG count;
642 IWbemClassObject *obj;
643 struct table *table;
644 VARIANT var;
646 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
647 if (!count) break;
649 if ((hr = IWbemClassObject_Get( obj, L"AssocClass", 0, &var, NULL, NULL )) != S_OK)
651 IWbemClassObject_Release( obj );
652 goto done;
654 IWbemClassObject_Release( obj );
656 hr = get_antecedent_table( V_BSTR(&var), view->path, &table );
657 VariantClear( &var );
658 if (hr != S_OK) goto done;
660 if (table && (hr = append_table( view, table )) != S_OK)
662 release_table( table );
663 goto done;
667 if (view->table_count)
669 if (!(view->result = heap_alloc_zero( view->table_count * sizeof(UINT) ))) hr = E_OUTOFMEMORY;
670 else view->result_count = view->table_count;
673 done:
674 if (iter) IEnumWbemClassObject_Release( iter );
675 free_path( path );
676 return hr;
679 static HRESULT exec_select_view( struct view *view )
681 UINT i, j = 0, len;
682 enum fill_status status = FILL_STATUS_UNFILTERED;
683 struct table *table;
685 if (!view->table_count) return S_OK;
687 table = view->table[0];
688 if (table->fill)
690 clear_table( table );
691 status = table->fill( table, view->cond );
693 if (status == FILL_STATUS_FAILED) return WBEM_E_FAILED;
694 if (!table->num_rows) return S_OK;
696 len = min( table->num_rows, 16 );
697 if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
699 for (i = 0; i < table->num_rows; i++)
701 HRESULT hr;
702 LONGLONG val = 0;
703 UINT type;
705 if (j >= len)
707 UINT *tmp;
708 len *= 2;
709 if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
710 view->result = tmp;
712 if (status == FILL_STATUS_FILTERED) val = 1;
713 else if ((hr = eval_cond( table, i, view->cond, &val, &type )) != S_OK) return hr;
714 if (val) view->result[j++] = i;
717 view->result_count = j;
718 return S_OK;
721 HRESULT execute_view( struct view *view )
723 switch (view->type)
725 case VIEW_TYPE_ASSOCIATORS:
726 return exec_assoc_view( view );
728 case VIEW_TYPE_SELECT:
729 return exec_select_view( view );
731 default:
732 ERR( "unhandled type %u\n", view->type );
733 return E_INVALIDARG;
737 struct query *create_query(void)
739 struct query *query;
741 if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
742 list_init( &query->mem );
743 query->refs = 1;
744 return query;
747 void free_query( struct query *query )
749 struct list *mem, *next;
751 if (!query) return;
752 destroy_view( query->view );
753 LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { heap_free( mem ); }
754 heap_free( query );
757 struct query *addref_query( struct query *query )
759 InterlockedIncrement( &query->refs );
760 return query;
763 void release_query( struct query *query )
765 if (!InterlockedDecrement( &query->refs )) free_query( query );
768 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
770 HRESULT hr;
771 struct query *query;
773 *result = NULL;
774 if (!(query = create_query())) return E_OUTOFMEMORY;
775 hr = parse_query( str, &query->view, &query->mem );
776 if (hr != S_OK) goto done;
777 hr = execute_view( query->view );
778 if (hr != S_OK) goto done;
779 hr = EnumWbemClassObject_create( query, (void **)result );
781 done:
782 release_query( query );
783 return hr;
786 BOOL is_result_prop( const struct view *view, const WCHAR *name )
788 const struct property *prop = view->proplist;
789 if (!prop) return TRUE;
790 while (prop)
792 if (!wcsicmp( prop->name, name )) return TRUE;
793 prop = prop->next;
795 return FALSE;
798 static BOOL is_system_prop( const WCHAR *name )
800 return (name[0] == '_' && name[1] == '_');
803 static BSTR build_proplist( const struct table *table, UINT row, UINT count, UINT *len )
805 UINT i, j, offset;
806 BSTR *values, ret = NULL;
808 if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
810 *len = j = 0;
811 for (i = 0; i < table->num_cols; i++)
813 if (table->columns[i].type & COL_FLAG_KEY)
815 const WCHAR *name = table->columns[i].name;
816 values[j] = get_value_bstr( table, row, i );
817 *len += lstrlenW( L"%s=%s" ) + lstrlenW( name ) + lstrlenW( values[j] );
818 j++;
821 if ((ret = SysAllocStringLen( NULL, *len )))
823 offset = j = 0;
824 for (i = 0; i < table->num_cols; i++)
826 if (table->columns[i].type & COL_FLAG_KEY)
828 const WCHAR *name = table->columns[i].name;
829 offset += swprintf( ret + offset, *len - offset, L"%s=%s", name, values[j] );
830 if (j < count - 1) ret[offset++] = ',';
831 j++;
835 for (i = 0; i < count; i++) SysFreeString( values[i] );
836 heap_free( values );
837 return ret;
840 static UINT count_key_columns( const struct table *table )
842 UINT i, num_keys = 0;
844 for (i = 0; i < table->num_cols; i++)
846 if (table->columns[i].type & COL_FLAG_KEY) num_keys++;
848 return num_keys;
851 static BSTR build_relpath( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
853 BSTR class, proplist, ret = NULL;
854 struct table *table = view->table[table_index];
855 UINT row = view->result[result_index];
856 UINT num_keys, len;
858 if (view->proplist) return NULL;
860 if (!(class = SysAllocString( view->table[table_index]->name ))) return NULL;
861 if (!(num_keys = count_key_columns( table ))) return class;
862 if (!(proplist = build_proplist( table, row, num_keys, &len ))) goto done;
864 len += lstrlenW( L"%s.%s" ) + SysStringLen( class );
865 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
866 swprintf( ret, len, L"%s.%s", class, proplist );
868 done:
869 SysFreeString( class );
870 SysFreeString( proplist );
871 return ret;
874 static BSTR build_path( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
876 BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
877 UINT len;
879 if (view->proplist) return NULL;
881 if (!(server = build_servername())) return NULL;
882 if (!(namespace = build_namespace())) goto done;
883 if (!(relpath = build_relpath( view, table_index, result_index, name ))) goto done;
885 len = lstrlenW( L"\\\\%s\\%s:%s" ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
886 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
887 swprintf( ret, len, L"\\\\%s\\%s:%s", server, namespace, relpath );
889 done:
890 SysFreeString( server );
891 SysFreeString( namespace );
892 SysFreeString( relpath );
893 return ret;
896 BOOL is_method( const struct table *table, UINT column )
898 return table->columns[column].type & COL_FLAG_METHOD;
901 static UINT count_properties( const struct table *table )
903 UINT i, num_props = 0;
905 for (i = 0; i < table->num_cols; i++)
907 if (!is_method( table, i )) num_props++;
909 return num_props;
912 static UINT count_result_properties( const struct view *view, UINT table_index )
914 const struct property *prop = view->proplist;
915 UINT count;
917 if (!prop) return count_properties( view->table[table_index] );
919 count = 1;
920 while ((prop = prop->next)) count++;
921 return count;
924 static HRESULT get_system_propval( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name,
925 VARIANT *ret, CIMTYPE *type, LONG *flavor )
927 if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
929 if (!wcsicmp( name, L"__CLASS" ))
931 if (ret)
933 V_VT( ret ) = VT_BSTR;
934 V_BSTR( ret ) = SysAllocString( view->table[table_index]->name );
936 if (type) *type = CIM_STRING;
937 return S_OK;
939 if (!wcsicmp( name, L"__GENUS" ))
941 if (ret)
943 V_VT( ret ) = VT_I4;
944 V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
946 if (type) *type = CIM_SINT32;
947 return S_OK;
949 if (!wcsicmp( name, L"__NAMESPACE" ))
951 if (ret)
953 V_VT( ret ) = VT_BSTR;
954 V_BSTR( ret ) = view->proplist ? NULL : build_namespace();
955 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
957 if (type) *type = CIM_STRING;
958 return S_OK;
960 if (!wcsicmp( name, L"__PATH" ))
962 if (ret)
964 V_VT( ret ) = VT_BSTR;
965 V_BSTR( ret ) = build_path( view, table_index, result_index, name );
966 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
968 if (type) *type = CIM_STRING;
969 return S_OK;
971 if (!wcsicmp( name, L"__PROPERTY_COUNT" ))
973 if (ret)
975 V_VT( ret ) = VT_I4;
976 V_I4( ret ) = count_result_properties( view, table_index );
978 if (type) *type = CIM_SINT32;
979 return S_OK;
981 if (!wcsicmp( name, L"__RELPATH" ))
983 if (ret)
985 V_VT( ret ) = VT_BSTR;
986 V_BSTR( ret ) = build_relpath( view, table_index, result_index, name );
987 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
989 if (type) *type = CIM_STRING;
990 return S_OK;
992 if (!wcsicmp( name, L"__SERVER" ))
994 if (ret)
996 V_VT( ret ) = VT_BSTR;
997 V_BSTR( ret ) = view->proplist ? NULL : build_servername();
998 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
1000 if (type) *type = CIM_STRING;
1001 return S_OK;
1003 FIXME("system property %s not implemented\n", debugstr_w(name));
1004 return WBEM_E_NOT_FOUND;
1007 VARTYPE to_vartype( CIMTYPE type )
1009 switch (type)
1011 case CIM_BOOLEAN: return VT_BOOL;
1013 case CIM_STRING:
1014 case CIM_REFERENCE:
1015 case CIM_DATETIME: return VT_BSTR;
1017 case CIM_SINT8: return VT_I1;
1018 case CIM_UINT8: return VT_UI1;
1019 case CIM_SINT16: return VT_I2;
1021 case CIM_UINT16:
1022 case CIM_SINT32:
1023 case CIM_UINT32: return VT_I4;
1025 case CIM_SINT64: return VT_I8;
1026 case CIM_UINT64: return VT_UI8;
1028 case CIM_REAL32: return VT_R4;
1030 default:
1031 ERR("unhandled type %u\n", type);
1032 break;
1034 return 0;
1037 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE basetype )
1039 SAFEARRAY *ret;
1040 VARTYPE vartype = to_vartype( basetype );
1041 LONG i;
1043 if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
1045 for (i = 0; i < array->count; i++)
1047 void *ptr = (char *)array->ptr + i * array->elem_size;
1048 if (vartype == VT_BSTR)
1050 BSTR str = SysAllocString( *(const WCHAR **)ptr );
1051 if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
1053 SysFreeString( str );
1054 SafeArrayDestroy( ret );
1055 return NULL;
1057 SysFreeString( str );
1059 else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
1061 SafeArrayDestroy( ret );
1062 return NULL;
1065 return ret;
1068 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
1070 if (type & VT_ARRAY)
1072 V_VT( ret ) = type;
1073 V_ARRAY( ret ) = val_ptr;
1074 return;
1076 switch (type)
1078 case VT_BOOL:
1079 V_BOOL( ret ) = val;
1080 break;
1081 case VT_BSTR:
1082 V_BSTR( ret ) = val_ptr;
1083 break;
1084 case VT_I1:
1085 V_I1( ret ) = val;
1086 break;
1087 case VT_UI1:
1088 V_UI1( ret ) = val;
1089 break;
1090 case VT_I2:
1091 V_I2( ret ) = val;
1092 break;
1093 case VT_UI2:
1094 V_UI2( ret ) = val;
1095 break;
1096 case VT_I4:
1097 V_I4( ret ) = val;
1098 break;
1099 case VT_UI4:
1100 V_UI4( ret ) = val;
1101 break;
1102 case VT_NULL:
1103 break;
1104 case VT_R4:
1105 V_R4( ret ) = *(FLOAT *)&val;
1106 break;
1107 default:
1108 ERR("unhandled variant type %u\n", type);
1109 return;
1111 V_VT( ret ) = type;
1114 static HRESULT map_view_index( const struct view *view, UINT index, UINT *table_index, UINT *result_index )
1116 if (!view->table) return WBEM_E_NOT_FOUND;
1118 switch (view->type)
1120 case VIEW_TYPE_SELECT:
1121 *table_index = 0;
1122 *result_index = index;
1123 break;
1125 case VIEW_TYPE_ASSOCIATORS:
1126 *table_index = *result_index = index;
1127 break;
1129 default:
1130 ERR( "unhandled view type %u\n", view->type );
1131 return WBEM_E_FAILED;
1133 return S_OK;
1136 struct table *get_view_table( const struct view *view, UINT index )
1138 switch (view->type)
1140 case VIEW_TYPE_SELECT:
1141 return view->table[0];
1143 case VIEW_TYPE_ASSOCIATORS:
1144 return view->table[index];
1146 default:
1147 ERR( "unhandled view type %u\n", view->type );
1148 return NULL;
1152 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type,
1153 LONG *flavor )
1155 HRESULT hr;
1156 UINT column, row, table_index, result_index;
1157 struct table *table;
1158 VARTYPE vartype;
1159 void *val_ptr = NULL;
1160 LONGLONG val;
1162 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1164 if (is_system_prop( name )) return get_system_propval( view, table_index, result_index, name, ret, type, flavor );
1165 if (!view->result_count || !is_result_prop( view, name )) return WBEM_E_NOT_FOUND;
1167 table = view->table[table_index];
1168 hr = get_column_index( table, name, &column );
1169 if (hr != S_OK || is_method( table, column )) return WBEM_E_NOT_FOUND;
1171 row = view->result[result_index];
1172 hr = get_value( table, row, column, &val );
1173 if (hr != S_OK) return hr;
1175 if (type) *type = table->columns[column].type & COL_TYPE_MASK;
1176 if (flavor) *flavor = 0;
1178 if (!ret) return S_OK;
1180 vartype = to_vartype( table->columns[column].type & CIM_TYPE_MASK );
1181 if (table->columns[column].type & CIM_FLAG_ARRAY)
1183 CIMTYPE basetype = table->columns[column].type & CIM_TYPE_MASK;
1185 val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
1186 if (!val_ptr) vartype = VT_NULL;
1187 else vartype |= VT_ARRAY;
1188 set_variant( vartype, val, val_ptr, ret );
1189 return S_OK;
1192 switch (table->columns[column].type & COL_TYPE_MASK)
1194 case CIM_STRING:
1195 case CIM_REFERENCE:
1196 case CIM_DATETIME:
1197 if (val)
1199 vartype = VT_BSTR;
1200 val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
1202 else
1203 vartype = VT_NULL;
1204 break;
1205 case CIM_SINT64:
1206 vartype = VT_BSTR;
1207 val_ptr = get_value_bstr( table, row, column );
1208 break;
1209 case CIM_UINT64:
1210 vartype = VT_BSTR;
1211 val_ptr = get_value_bstr( table, row, column );
1212 break;
1213 case CIM_BOOLEAN:
1214 case CIM_SINT8:
1215 case CIM_UINT8:
1216 case CIM_SINT16:
1217 case CIM_UINT16:
1218 case CIM_SINT32:
1219 case CIM_UINT32:
1220 case CIM_REAL32:
1221 break;
1222 default:
1223 ERR("unhandled column type %u\n", table->columns[column].type);
1224 return WBEM_E_FAILED;
1227 set_variant( vartype, val, val_ptr, ret );
1228 return S_OK;
1231 static CIMTYPE to_cimtype( VARTYPE type )
1233 switch (type)
1235 case VT_BOOL: return CIM_BOOLEAN;
1236 case VT_BSTR: return CIM_STRING;
1237 case VT_I1: return CIM_SINT8;
1238 case VT_UI1: return CIM_UINT8;
1239 case VT_I2: return CIM_SINT16;
1240 case VT_UI2: return CIM_UINT16;
1241 case VT_I4: return CIM_SINT32;
1242 case VT_UI4: return CIM_UINT32;
1243 case VT_I8: return CIM_SINT64;
1244 case VT_UI8: return CIM_UINT64;
1245 default:
1246 ERR("unhandled type %u\n", type);
1247 break;
1249 return 0;
1252 static struct array *to_array( VARIANT *var, CIMTYPE *type )
1254 struct array *ret;
1255 LONG bound, i;
1256 VARTYPE vartype;
1257 CIMTYPE basetype;
1259 if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
1260 if (!(basetype = to_cimtype( vartype ))) return NULL;
1261 if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
1262 if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
1264 ret->count = bound + 1;
1265 ret->elem_size = get_type_size( basetype );
1266 if (!(ret->ptr = heap_alloc_zero( ret->count * ret->elem_size )))
1268 heap_free( ret );
1269 return NULL;
1271 for (i = 0; i < ret->count; i++)
1273 void *ptr = (char *)ret->ptr + i * ret->elem_size;
1274 if (vartype == VT_BSTR)
1276 BSTR str;
1277 if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
1279 destroy_array( ret, basetype );
1280 return NULL;
1282 *(WCHAR **)ptr = heap_strdupW( str );
1283 SysFreeString( str );
1284 if (!*(WCHAR **)ptr)
1286 destroy_array( ret, basetype );
1287 return NULL;
1290 else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
1292 destroy_array( ret, basetype );
1293 return NULL;
1296 *type = basetype | CIM_FLAG_ARRAY;
1297 return ret;
1300 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
1302 if (!var)
1304 *val = 0;
1305 return S_OK;
1307 if (V_VT( var ) & VT_ARRAY)
1309 *val = (INT_PTR)to_array( var, type );
1310 if (!*val) return E_OUTOFMEMORY;
1311 return S_OK;
1313 switch (V_VT( var ))
1315 case VT_BOOL:
1316 *val = V_BOOL( var );
1317 *type = CIM_BOOLEAN;
1318 break;
1319 case VT_BSTR:
1320 *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
1321 if (!*val) return E_OUTOFMEMORY;
1322 *type = CIM_STRING;
1323 break;
1324 case VT_I2:
1325 *val = V_I2( var );
1326 *type = CIM_SINT16;
1327 break;
1328 case VT_UI2:
1329 *val = V_UI2( var );
1330 *type = CIM_UINT16;
1331 break;
1332 case VT_I4:
1333 *val = V_I4( var );
1334 *type = CIM_SINT32;
1335 break;
1336 case VT_UI4:
1337 *val = V_UI4( var );
1338 *type = CIM_UINT32;
1339 break;
1340 case VT_NULL:
1341 *val = 0;
1342 break;
1343 default:
1344 ERR("unhandled type %u\n", V_VT( var ));
1345 return WBEM_E_FAILED;
1347 return S_OK;
1350 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
1352 HRESULT hr;
1353 UINT row, column, table_index, result_index;
1354 struct table *table;
1355 LONGLONG val;
1357 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1359 table = view->table[table_index];
1360 hr = get_column_index( table, name, &column );
1361 if (hr != S_OK)
1363 FIXME("no support for creating new properties\n");
1364 return WBEM_E_FAILED;
1366 if (is_method( table, column ) || !(table->columns[column].type & COL_FLAG_DYNAMIC))
1367 return WBEM_E_FAILED;
1369 hr = to_longlong( var, &val, &type );
1370 if (hr != S_OK) return hr;
1372 row = view->result[result_index];
1373 return set_value( table, row, column, val, type );
1376 HRESULT get_properties( const struct view *view, UINT index, LONG flags, SAFEARRAY **props )
1378 static const WCHAR * const system_props[] =
1379 { L"__GENUS", L"__CLASS", L"__RELPATH", L"__PROPERTY_COUNT", L"__SERVER", L"__NAMESPACE", L"__PATH" };
1380 SAFEARRAY *sa;
1381 BSTR str;
1382 UINT i, table_index, result_index, count = 0;
1383 struct table *table;
1384 HRESULT hr;
1385 LONG j = 0;
1387 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1388 table = view->table[table_index];
1390 if (!(flags & WBEM_FLAG_NONSYSTEM_ONLY)) count += ARRAY_SIZE(system_props);
1391 if (!(flags & WBEM_FLAG_SYSTEM_ONLY))
1393 for (i = 0; i < table->num_cols; i++)
1395 if (!is_method( table, i ) && is_result_prop( view, table->columns[i].name )) count++;
1399 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, count ))) return E_OUTOFMEMORY;
1401 if (!(flags & WBEM_FLAG_NONSYSTEM_ONLY))
1403 for (j = 0; j < ARRAY_SIZE(system_props); j++)
1405 str = SysAllocString( system_props[j] );
1406 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1408 SysFreeString( str );
1409 SafeArrayDestroy( sa );
1410 return E_OUTOFMEMORY;
1412 SysFreeString( str );
1415 if (!(flags & WBEM_FLAG_SYSTEM_ONLY))
1417 for (i = 0; i < table->num_cols; i++)
1419 if (is_method( table, i ) || !is_result_prop( view, table->columns[i].name )) continue;
1421 str = SysAllocString( table->columns[i].name );
1422 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1424 SysFreeString( str );
1425 SafeArrayDestroy( sa );
1426 return E_OUTOFMEMORY;
1428 SysFreeString( str );
1429 j++;
1433 *props = sa;
1434 return S_OK;