vbscript: Handle index read access to array properties.
[wine.git] / dlls / wbemprox / query.c
blob1b79523d66fafd0016a3786b20510f0895fcf6f6
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 = 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, enum wbm_namespace ns, const WCHAR *path, const struct keyword *keywordlist,
42 const WCHAR *class, const struct property *proplist, const struct expr *cond, struct view **ret )
44 struct view *view = calloc( 1, 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( ns, class );
58 HRESULT hr;
60 if (table && (hr = append_table( view, table )) != S_OK)
62 free( view );
63 return hr;
65 else if (!table && ns == WBEMPROX_NAMESPACE_LAST) return WBEM_E_INVALID_CLASS;
66 view->proplist = proplist;
67 view->cond = cond;
68 break;
70 default:
71 ERR( "unhandled type %u\n", type );
72 free( view );
73 return E_INVALIDARG;
76 view->type = type;
77 view->ns = ns;
78 *ret = view;
79 return S_OK;
82 void destroy_view( struct view *view )
84 ULONG i;
85 if (!view) return;
86 for (i = 0; i < view->table_count; i++) release_table( view->table[i] );
87 free( view->table );
88 free( view->result );
89 free( view );
92 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
94 const WCHAR *p = lstr, *q = rstr;
96 while (*p && *q)
98 if (q[0] == '\\' && q[1] == '\\') q++;
99 if (*q == '%')
101 while (*q == '%') q++;
102 if (!*q) return TRUE;
103 while (*p && *q && towupper( *p ) == towupper( *q )) { p++; q++; };
104 if (!*p && !*q) return TRUE;
106 if (*q != '%' && towupper( *p++ ) != towupper( *q++ )) return FALSE;
108 return TRUE;
111 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
113 if (!lstr || !rstr)
115 *val = 0;
116 return S_OK;
118 switch (op)
120 case OP_EQ:
121 *val = !wcsicmp( lstr, rstr );
122 break;
123 case OP_GT:
124 *val = wcsicmp( lstr, rstr ) > 0;
125 break;
126 case OP_LT:
127 *val = wcsicmp( lstr, rstr ) < 0;
128 break;
129 case OP_LE:
130 *val = wcsicmp( lstr, rstr ) <= 0;
131 break;
132 case OP_GE:
133 *val = wcsicmp( lstr, rstr ) >= 0;
134 break;
135 case OP_NE:
136 *val = wcsicmp( lstr, rstr );
137 break;
138 case OP_LIKE:
139 *val = eval_like( lstr, rstr );
140 break;
141 default:
142 ERR("unhandled operator %u\n", op);
143 return WBEM_E_INVALID_QUERY;
145 return S_OK;
148 static BOOL is_int( CIMTYPE type )
150 switch (type)
152 case CIM_SINT8:
153 case CIM_SINT16:
154 case CIM_SINT32:
155 case CIM_SINT64:
156 case CIM_UINT8:
157 case CIM_UINT16:
158 case CIM_UINT32:
159 case CIM_UINT64:
160 return TRUE;
161 default:
162 return FALSE;
166 static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
168 if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL &&
169 expr->right->type == EXPR_SVAL) return TRUE;
170 else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL &&
171 expr->left->type == EXPR_SVAL) return TRUE;
172 return FALSE;
175 static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
177 if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL &&
178 (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE;
179 else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL &&
180 (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE;
181 return FALSE;
184 static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val )
186 if (ltype == CIM_STRING) lval = !wcsicmp( (const WCHAR *)(INT_PTR)lval, L"True" ) ? -1 : 0;
187 else if (rtype == CIM_STRING) rval = !wcsicmp( (const WCHAR *)(INT_PTR)rval, L"True" ) ? -1 : 0;
189 switch (op)
191 case OP_EQ:
192 *val = (lval == rval);
193 break;
194 case OP_NE:
195 *val = (lval != rval);
196 break;
197 default:
198 ERR("unhandled operator %u\n", op);
199 return WBEM_E_INVALID_QUERY;
201 return S_OK;
204 static inline BOOL is_refcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
206 if (ltype == CIM_REFERENCE && expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) return TRUE;
207 else if (rtype == CIM_REFERENCE && expr->right->type == EXPR_PROPVAL && expr->left->type == EXPR_SVAL) return TRUE;
208 return FALSE;
211 static HRESULT eval_refcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
213 if (!lstr || !rstr)
215 *val = 0;
216 return S_OK;
218 switch (op)
220 case OP_EQ:
221 *val = !wcsicmp( lstr, rstr );
222 break;
223 case OP_NE:
224 *val = wcsicmp( lstr, rstr );
225 break;
226 default:
227 ERR("unhandled operator %u\n", op);
228 return WBEM_E_INVALID_QUERY;
230 return S_OK;
233 static UINT resolve_type( UINT left, UINT right )
235 switch (left)
237 case CIM_SINT8:
238 case CIM_SINT16:
239 case CIM_SINT32:
240 case CIM_SINT64:
241 case CIM_UINT8:
242 case CIM_UINT16:
243 case CIM_UINT32:
244 case CIM_UINT64:
245 switch (right)
247 case CIM_SINT8:
248 case CIM_SINT16:
249 case CIM_SINT32:
250 case CIM_SINT64:
251 case CIM_UINT8:
252 case CIM_UINT16:
253 case CIM_UINT32:
254 case CIM_UINT64:
255 return CIM_UINT64;
256 default: break;
258 break;
260 case CIM_STRING:
261 if (right == CIM_STRING) return CIM_STRING;
262 break;
264 case CIM_BOOLEAN:
265 if (right == CIM_BOOLEAN) return CIM_BOOLEAN;
266 break;
268 case CIM_REFERENCE:
269 if (right == CIM_REFERENCE) return CIM_REFERENCE;
270 break;
272 default:
273 break;
275 return CIM_ILLEGAL;
278 static const WCHAR *format_int( WCHAR *buf, UINT len, CIMTYPE type, LONGLONG val )
280 switch (type)
282 case CIM_SINT8:
283 case CIM_SINT16:
284 case CIM_SINT32:
285 swprintf( buf, len, L"%d", val );
286 return buf;
288 case CIM_UINT8:
289 case CIM_UINT16:
290 case CIM_UINT32:
291 swprintf( buf, len, L"%u", val );
292 return buf;
294 case CIM_SINT64:
295 wsprintfW( buf, L"%I64d", val );
296 return buf;
298 case CIM_UINT64:
299 wsprintfW( buf, L"%I64u", val );
300 return buf;
302 default:
303 ERR( "unhandled type %lu\n", type );
304 return NULL;
308 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
309 LONGLONG *val, UINT *type )
311 HRESULT lret, rret;
312 LONGLONG lval, rval;
313 UINT ltype, rtype;
315 lret = eval_cond( table, row, expr->left, &lval, &ltype );
316 rret = eval_cond( table, row, expr->right, &rval, &rtype );
317 if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
319 *type = resolve_type( ltype, rtype );
321 if (is_strcmp( expr, ltype, rtype ))
323 const WCHAR *lstr, *rstr;
324 WCHAR lbuf[21], rbuf[21];
326 if (is_int( ltype )) lstr = format_int( lbuf, ARRAY_SIZE( lbuf ), ltype, lval );
327 else lstr = (const WCHAR *)(INT_PTR)lval;
329 if (is_int( rtype )) rstr = format_int( rbuf, ARRAY_SIZE( rbuf ), rtype, rval );
330 else rstr = (const WCHAR *)(INT_PTR)rval;
332 return eval_strcmp( expr->op, lstr, rstr, val );
334 if (is_boolcmp( expr, ltype, rtype ))
336 return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val );
338 if (is_refcmp( expr, ltype, rtype ))
340 return eval_refcmp( expr->op, (const WCHAR *)(INT_PTR)lval, (const WCHAR *)(INT_PTR)rval, val );
343 switch (expr->op)
345 case OP_EQ:
346 *val = (lval == rval);
347 break;
348 case OP_AND:
349 *val = (lval && rval);
350 break;
351 case OP_OR:
352 *val = (lval || rval);
353 break;
354 case OP_GT:
355 *val = (lval > rval);
356 break;
357 case OP_LT:
358 *val = (lval < rval);
359 break;
360 case OP_LE:
361 *val = (lval <= rval);
362 break;
363 case OP_GE:
364 *val = (lval >= rval);
365 break;
366 case OP_NE:
367 *val = (lval != rval);
368 break;
369 default:
370 ERR("unhandled operator %u\n", expr->op);
371 return WBEM_E_INVALID_QUERY;
373 return S_OK;
376 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
377 LONGLONG *val, UINT *type )
380 HRESULT hr;
381 UINT column;
382 LONGLONG lval;
384 if (expr->op == OP_NOT)
386 hr = eval_cond( table, row, expr->left, &lval, type );
387 if (hr != S_OK)
388 return hr;
389 *val = !lval;
390 return S_OK;
393 hr = get_column_index( table, expr->left->u.propval->name, &column );
394 if (hr != S_OK)
395 return hr;
397 hr = get_value( table, row, column, &lval );
398 if (hr != S_OK)
399 return hr;
401 switch (expr->op)
403 case OP_ISNULL:
404 *val = !lval;
405 break;
406 case OP_NOTNULL:
407 *val = lval;
408 break;
409 default:
410 ERR("unknown operator %u\n", expr->op);
411 return WBEM_E_INVALID_QUERY;
414 *type = table->columns[column].type & CIM_TYPE_MASK;
415 return S_OK;
418 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
419 LONGLONG *val, UINT *type )
422 HRESULT hr;
423 UINT column;
425 hr = get_column_index( table, propval->name, &column );
426 if (hr != S_OK)
427 return hr;
429 *type = table->columns[column].type & CIM_TYPE_MASK;
430 return get_value( table, row, column, val );
433 HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type )
435 if (!cond)
437 *val = 1;
438 *type = CIM_UINT64;
439 return S_OK;
441 switch (cond->type)
443 case EXPR_COMPLEX:
444 return eval_binary( table, row, &cond->u.expr, val, type );
446 case EXPR_UNARY:
447 return eval_unary( table, row, &cond->u.expr, val, type );
449 case EXPR_PROPVAL:
450 return eval_propval( table, row, cond->u.propval, val, type );
452 case EXPR_SVAL:
453 *val = (INT_PTR)cond->u.sval;
454 *type = CIM_STRING;
455 return S_OK;
457 case EXPR_IVAL:
458 *val = cond->u.ival;
459 *type = CIM_UINT64;
460 return S_OK;
462 case EXPR_BVAL:
463 *val = cond->u.ival;
464 *type = CIM_BOOLEAN;
465 return S_OK;
467 default:
468 ERR("invalid expression type\n");
469 break;
471 return WBEM_E_INVALID_QUERY;
474 static WCHAR *build_assoc_query( const WCHAR *class, UINT class_len )
476 static const WCHAR fmtW[] = L"SELECT * FROM __ASSOCIATORS WHERE Class='%s'";
477 UINT len = class_len + ARRAY_SIZE(fmtW);
478 WCHAR *ret;
480 if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL;
481 swprintf( ret, len, fmtW, class );
482 return ret;
485 static HRESULT create_assoc_enum( enum wbm_namespace ns, const WCHAR *class, UINT class_len,
486 IEnumWbemClassObject **iter )
488 WCHAR *query;
489 HRESULT hr;
491 if (!(query = build_assoc_query( class, class_len ))) return E_OUTOFMEMORY;
492 hr = exec_query( ns, query, iter );
493 free( query );
494 return hr;
497 static WCHAR *build_antecedent_query( const WCHAR *assocclass, const WCHAR *dependent )
499 static const WCHAR fmtW[] = L"SELECT Antecedent FROM %s WHERE Dependent='%s'";
500 UINT len = lstrlenW(assocclass) + lstrlenW(dependent) + ARRAY_SIZE(fmtW);
501 WCHAR *ret;
503 if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL;
504 swprintf( ret, len, fmtW, assocclass, dependent );
505 return ret;
508 static BSTR build_servername(void)
510 WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
511 DWORD len = ARRAY_SIZE( server );
513 if (!(GetComputerNameW( server, &len ))) return NULL;
514 for (p = server; *p; p++) *p = towupper( *p );
515 return SysAllocString( server );
518 static BSTR build_namespace(void)
520 return SysAllocString( L"ROOT\\CIMV2" );
523 static WCHAR *build_canonical_path( const WCHAR *relpath )
525 BSTR server, namespace;
526 WCHAR *ret;
527 UINT len, i;
529 if (!(server = build_servername())) return NULL;
530 if (!(namespace = build_namespace()))
532 SysFreeString( server );
533 return NULL;
536 len = ARRAY_SIZE( L"\\\\%s\\%s:" ) + SysStringLen( server ) + SysStringLen( namespace ) + lstrlenW( relpath );
537 if ((ret = malloc( len * sizeof(WCHAR ) )))
539 len = swprintf( ret, len, L"\\\\%s\\%s:", server, namespace );
540 for (i = 0; i < lstrlenW( relpath ); i ++)
542 if (relpath[i] == '\'') ret[len++] = '"';
543 else ret[len++] = relpath[i];
545 ret[len] = 0;
548 SysFreeString( server );
549 SysFreeString( namespace );
550 return ret;
553 static HRESULT get_antecedent( enum wbm_namespace ns, const WCHAR *assocclass, const WCHAR *dependent, BSTR *ret )
555 WCHAR *fullpath, *str;
556 IEnumWbemClassObject *iter = NULL;
557 IWbemClassObject *obj;
558 HRESULT hr = E_OUTOFMEMORY;
559 ULONG count;
560 VARIANT var;
562 if (!(fullpath = build_canonical_path( dependent ))) return E_OUTOFMEMORY;
563 if (!(str = build_antecedent_query( assocclass, fullpath ))) goto done;
564 if ((hr = exec_query( ns, str, &iter )) != S_OK) goto done;
566 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
567 if (!count)
569 *ret = NULL;
570 goto done;
573 hr = IWbemClassObject_Get( obj, L"Antecedent", 0, &var, NULL, NULL );
574 IWbemClassObject_Release( obj );
575 if (hr != S_OK) goto done;
576 *ret = V_BSTR( &var );
578 done:
579 if (iter) IEnumWbemClassObject_Release( iter );
580 free( str );
581 free( fullpath );
582 return hr;
585 static HRESULT do_query( enum wbm_namespace ns, const WCHAR *str, struct query **ret_query )
587 struct query *query;
588 HRESULT hr;
590 if (!(query = create_query( ns ))) return E_OUTOFMEMORY;
591 if ((hr = parse_query( ns, str, &query->view, &query->mem )) != S_OK || (hr = execute_view( query->view )) != S_OK)
593 release_query( query );
594 return hr;
596 *ret_query = query;
597 return S_OK;
600 static HRESULT get_antecedent_table( enum wbm_namespace ns, const WCHAR *assocclass, const WCHAR *dependent,
601 struct table **table )
603 BSTR antecedent = NULL;
604 struct path *path = NULL;
605 WCHAR *str = NULL;
606 struct query *query = NULL;
607 HRESULT hr;
609 if ((hr = get_antecedent( ns, assocclass, dependent, &antecedent )) != S_OK) return hr;
610 if (!antecedent)
612 *table = NULL;
613 return S_OK;
615 if ((hr = parse_path( antecedent, &path )) != S_OK) goto done;
616 if (!(str = query_from_path( path )))
618 hr = E_OUTOFMEMORY;
619 goto done;
622 if ((hr = do_query( ns, str, &query )) != S_OK) goto done;
623 if (query->view->table_count) *table = addref_table( query->view->table[0] );
624 else *table = NULL;
626 done:
627 if (query) release_query( query );
628 free_path( path );
629 SysFreeString( antecedent );
630 free( str );
631 return hr;
634 static HRESULT exec_assoc_view( struct view *view )
636 IEnumWbemClassObject *iter = NULL;
637 struct path *path;
638 HRESULT hr;
640 if (view->keywordlist) FIXME( "ignoring keywords\n" );
641 if ((hr = parse_path( view->path, &path )) != S_OK) return hr;
643 if ((hr = create_assoc_enum( view->ns, path->class, path->class_len, &iter )) != S_OK) goto done;
644 for (;;)
646 ULONG count;
647 IWbemClassObject *obj;
648 struct table *table;
649 VARIANT var;
651 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
652 if (!count) break;
654 if ((hr = IWbemClassObject_Get( obj, L"AssocClass", 0, &var, NULL, NULL )) != S_OK)
656 IWbemClassObject_Release( obj );
657 goto done;
659 IWbemClassObject_Release( obj );
661 hr = get_antecedent_table( view->ns, V_BSTR(&var), view->path, &table );
662 VariantClear( &var );
663 if (hr != S_OK) goto done;
665 if (table && (hr = append_table( view, table )) != S_OK)
667 release_table( table );
668 goto done;
672 if (view->table_count)
674 if (!(view->result = calloc( view->table_count, sizeof(UINT) ))) hr = E_OUTOFMEMORY;
675 else view->result_count = view->table_count;
678 done:
679 if (iter) IEnumWbemClassObject_Release( iter );
680 free_path( path );
681 return hr;
684 static HRESULT exec_select_view( struct view *view )
686 UINT i, j = 0, len;
687 enum fill_status status = FILL_STATUS_UNFILTERED;
688 struct table *table;
690 if (!view->table_count) return S_OK;
692 table = view->table[0];
693 if (table->fill)
695 clear_table( table );
696 status = table->fill( table, view->cond );
698 if (status == FILL_STATUS_FAILED) return WBEM_E_FAILED;
699 if (!table->num_rows) return S_OK;
701 len = min( table->num_rows, 16 );
702 if (!(view->result = malloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
704 for (i = 0; i < table->num_rows; i++)
706 HRESULT hr;
707 LONGLONG val = 0;
708 UINT type;
710 if (j >= len)
712 UINT *tmp;
713 len *= 2;
714 if (!(tmp = realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
715 view->result = tmp;
717 if (status == FILL_STATUS_FILTERED) val = 1;
718 else if ((hr = eval_cond( table, i, view->cond, &val, &type )) != S_OK) return hr;
719 if (val) view->result[j++] = i;
722 view->result_count = j;
723 return S_OK;
726 HRESULT execute_view( struct view *view )
728 switch (view->type)
730 case VIEW_TYPE_ASSOCIATORS:
731 return exec_assoc_view( view );
733 case VIEW_TYPE_SELECT:
734 return exec_select_view( view );
736 default:
737 ERR( "unhandled type %u\n", view->type );
738 return E_INVALIDARG;
742 struct query *create_query( enum wbm_namespace ns )
744 struct query *query;
746 if (!(query = malloc( sizeof(*query) ))) return NULL;
747 list_init( &query->mem );
748 query->ns = ns;
749 query->refs = 1;
750 return query;
753 void free_query( struct query *query )
755 struct list *mem, *next;
757 if (!query) return;
758 destroy_view( query->view );
759 LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { free( mem ); }
760 free( query );
763 struct query *addref_query( struct query *query )
765 InterlockedIncrement( &query->refs );
766 return query;
769 void release_query( struct query *query )
771 if (!InterlockedDecrement( &query->refs )) free_query( query );
774 HRESULT exec_query( enum wbm_namespace ns, const WCHAR *str, IEnumWbemClassObject **result )
776 HRESULT hr;
777 struct query *query;
779 *result = NULL;
780 if (!(query = create_query( ns ))) return E_OUTOFMEMORY;
781 hr = parse_query( ns, str, &query->view, &query->mem );
782 if (hr != S_OK) goto done;
783 hr = execute_view( query->view );
784 if (hr != S_OK) goto done;
785 hr = EnumWbemClassObject_create( query, (void **)result );
787 done:
788 release_query( query );
789 return hr;
792 BOOL is_result_prop( const struct view *view, const WCHAR *name )
794 const struct property *prop = view->proplist;
795 if (!prop) return TRUE;
796 while (prop)
798 if (!wcsicmp( prop->name, name )) return TRUE;
799 prop = prop->next;
801 return FALSE;
804 static BOOL is_system_prop( const WCHAR *name )
806 return (name[0] == '_' && name[1] == '_');
809 static BSTR build_proplist( const struct table *table, UINT row, UINT count, UINT *len )
811 UINT i, j, offset;
812 BSTR *values, ret = NULL;
814 if (!(values = malloc( count * sizeof(BSTR) ))) return NULL;
816 *len = j = 0;
817 for (i = 0; i < table->num_cols; i++)
819 if (table->columns[i].type & COL_FLAG_KEY)
821 const WCHAR *name = table->columns[i].name;
822 values[j] = get_value_bstr( table, row, i );
823 *len += lstrlenW( L"%s=%s" ) + lstrlenW( name ) + lstrlenW( values[j] );
824 j++;
827 if ((ret = SysAllocStringLen( NULL, *len )))
829 offset = j = 0;
830 for (i = 0; i < table->num_cols; i++)
832 if (table->columns[i].type & COL_FLAG_KEY)
834 const WCHAR *name = table->columns[i].name;
835 offset += swprintf( ret + offset, *len - offset, L"%s=%s", name, values[j] );
836 if (j < count - 1) ret[offset++] = ',';
837 j++;
841 for (i = 0; i < count; i++) SysFreeString( values[i] );
842 free( values );
843 return ret;
846 static UINT count_key_columns( const struct table *table )
848 UINT i, num_keys = 0;
850 for (i = 0; i < table->num_cols; i++)
852 if (table->columns[i].type & COL_FLAG_KEY) num_keys++;
854 return num_keys;
857 static BSTR build_relpath( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
859 BSTR class, proplist, ret = NULL;
860 struct table *table = view->table[table_index];
861 UINT row = view->result[result_index];
862 UINT num_keys, len;
864 if (view->proplist) return NULL;
866 if (!(class = SysAllocString( view->table[table_index]->name ))) return NULL;
867 if (!(num_keys = count_key_columns( table ))) return class;
868 if (!(proplist = build_proplist( table, row, num_keys, &len ))) goto done;
870 len += lstrlenW( L"%s.%s" ) + SysStringLen( class );
871 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
872 swprintf( ret, len, L"%s.%s", class, proplist );
874 done:
875 SysFreeString( class );
876 SysFreeString( proplist );
877 return ret;
880 static BSTR build_path( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
882 BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
883 UINT len;
885 if (view->proplist) return NULL;
887 if (!(server = build_servername())) return NULL;
888 if (!(namespace = build_namespace())) goto done;
889 if (!(relpath = build_relpath( view, table_index, result_index, name ))) goto done;
891 len = lstrlenW( L"\\\\%s\\%s:%s" ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
892 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
893 swprintf( ret, len, L"\\\\%s\\%s:%s", server, namespace, relpath );
895 done:
896 SysFreeString( server );
897 SysFreeString( namespace );
898 SysFreeString( relpath );
899 return ret;
902 BOOL is_method( const struct table *table, UINT column )
904 return table->columns[column].type & COL_FLAG_METHOD;
907 static UINT count_properties( const struct table *table )
909 UINT i, num_props = 0;
911 for (i = 0; i < table->num_cols; i++)
913 if (!is_method( table, i )) num_props++;
915 return num_props;
918 static UINT count_result_properties( const struct view *view, UINT table_index )
920 const struct property *prop = view->proplist;
921 UINT count;
923 if (!prop) return count_properties( view->table[table_index] );
925 count = 1;
926 while ((prop = prop->next)) count++;
927 return count;
930 static HRESULT get_system_propval( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name,
931 VARIANT *ret, CIMTYPE *type, LONG *flavor )
933 if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
935 if (!wcsicmp( name, L"__CLASS" ))
937 if (ret)
939 V_VT( ret ) = VT_BSTR;
940 V_BSTR( ret ) = SysAllocString( view->table[table_index]->name );
942 if (type) *type = CIM_STRING;
943 return S_OK;
945 if (!wcsicmp( name, L"__GENUS" ))
947 if (ret)
949 V_VT( ret ) = VT_I4;
950 V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
952 if (type) *type = CIM_SINT32;
953 return S_OK;
955 if (!wcsicmp( name, L"__NAMESPACE" ))
957 if (ret)
959 V_VT( ret ) = VT_BSTR;
960 V_BSTR( ret ) = view->proplist ? NULL : build_namespace();
961 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
963 if (type) *type = CIM_STRING;
964 return S_OK;
966 if (!wcsicmp( name, L"__PATH" ))
968 if (ret)
970 V_VT( ret ) = VT_BSTR;
971 V_BSTR( ret ) = build_path( view, table_index, result_index, name );
972 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
974 if (type) *type = CIM_STRING;
975 return S_OK;
977 if (!wcsicmp( name, L"__PROPERTY_COUNT" ))
979 if (ret)
981 V_VT( ret ) = VT_I4;
982 V_I4( ret ) = count_result_properties( view, table_index );
984 if (type) *type = CIM_SINT32;
985 return S_OK;
987 if (!wcsicmp( name, L"__RELPATH" ))
989 if (ret)
991 V_VT( ret ) = VT_BSTR;
992 V_BSTR( ret ) = build_relpath( view, table_index, result_index, name );
993 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
995 if (type) *type = CIM_STRING;
996 return S_OK;
998 if (!wcsicmp( name, L"__SERVER" ))
1000 if (ret)
1002 V_VT( ret ) = VT_BSTR;
1003 V_BSTR( ret ) = view->proplist ? NULL : build_servername();
1004 if (!V_BSTR( ret )) V_VT( ret ) = VT_NULL;
1006 if (type) *type = CIM_STRING;
1007 return S_OK;
1009 if (!wcsicmp( name, L"__DERIVATION" ))
1011 if (ret)
1013 SAFEARRAY *sa;
1014 FIXME( "returning empty array for __DERIVATION\n" );
1015 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, 0 ))) return E_OUTOFMEMORY;
1016 V_VT( ret ) = VT_BSTR | VT_ARRAY;
1017 V_ARRAY( ret ) = sa;
1019 if (type) *type = CIM_STRING | CIM_FLAG_ARRAY;
1020 return S_OK;
1022 FIXME("system property %s not implemented\n", debugstr_w(name));
1023 return WBEM_E_NOT_FOUND;
1026 VARTYPE to_vartype( CIMTYPE type )
1028 switch (type)
1030 case CIM_BOOLEAN: return VT_BOOL;
1032 case CIM_STRING:
1033 case CIM_REFERENCE:
1034 case CIM_DATETIME: return VT_BSTR;
1036 case CIM_SINT8: return VT_I1;
1037 case CIM_UINT8: return VT_UI1;
1038 case CIM_SINT16: return VT_I2;
1040 case CIM_UINT16:
1041 case CIM_SINT32:
1042 case CIM_UINT32: return VT_I4;
1044 case CIM_SINT64: return VT_I8;
1045 case CIM_UINT64: return VT_UI8;
1047 case CIM_REAL32: return VT_R4;
1049 default:
1050 ERR( "unhandled type %lu\n", type );
1051 break;
1053 return 0;
1056 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE basetype )
1058 SAFEARRAY *ret;
1059 VARTYPE vartype = to_vartype( basetype );
1060 LONG i;
1062 if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
1064 for (i = 0; i < array->count; i++)
1066 void *ptr = (char *)array->ptr + i * array->elem_size;
1067 if (vartype == VT_BSTR)
1069 BSTR str = SysAllocString( *(const WCHAR **)ptr );
1070 if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
1072 SysFreeString( str );
1073 SafeArrayDestroy( ret );
1074 return NULL;
1076 SysFreeString( str );
1078 else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
1080 SafeArrayDestroy( ret );
1081 return NULL;
1084 return ret;
1087 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
1089 if (type & VT_ARRAY)
1091 V_VT( ret ) = type;
1092 V_ARRAY( ret ) = val_ptr;
1093 return;
1095 switch (type)
1097 case VT_BOOL:
1098 V_BOOL( ret ) = val;
1099 break;
1100 case VT_BSTR:
1101 V_BSTR( ret ) = val_ptr;
1102 break;
1103 case VT_I1:
1104 V_I1( ret ) = val;
1105 break;
1106 case VT_UI1:
1107 V_UI1( ret ) = val;
1108 break;
1109 case VT_I2:
1110 V_I2( ret ) = val;
1111 break;
1112 case VT_UI2:
1113 V_UI2( ret ) = val;
1114 break;
1115 case VT_I4:
1116 V_I4( ret ) = val;
1117 break;
1118 case VT_UI4:
1119 V_UI4( ret ) = val;
1120 break;
1121 case VT_NULL:
1122 break;
1123 case VT_R4:
1124 V_R4( ret ) = *(FLOAT *)&val;
1125 break;
1126 default:
1127 ERR("unhandled variant type %u\n", type);
1128 return;
1130 V_VT( ret ) = type;
1133 static HRESULT map_view_index( const struct view *view, UINT index, UINT *table_index, UINT *result_index )
1135 if (!view->table) return WBEM_E_NOT_FOUND;
1137 switch (view->type)
1139 case VIEW_TYPE_SELECT:
1140 *table_index = 0;
1141 *result_index = index;
1142 break;
1144 case VIEW_TYPE_ASSOCIATORS:
1145 *table_index = *result_index = index;
1146 break;
1148 default:
1149 ERR( "unhandled view type %u\n", view->type );
1150 return WBEM_E_FAILED;
1152 return S_OK;
1155 struct table *get_view_table( const struct view *view, UINT index )
1157 switch (view->type)
1159 case VIEW_TYPE_SELECT:
1160 return view->table[0];
1162 case VIEW_TYPE_ASSOCIATORS:
1163 return view->table[index];
1165 default:
1166 ERR( "unhandled view type %u\n", view->type );
1167 return NULL;
1171 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type,
1172 LONG *flavor )
1174 HRESULT hr;
1175 UINT column, row, table_index, result_index;
1176 struct table *table;
1177 VARTYPE vartype;
1178 void *val_ptr = NULL;
1179 LONGLONG val;
1181 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1183 if (is_system_prop( name )) return get_system_propval( view, table_index, result_index, name, ret, type, flavor );
1184 if (!view->result_count || !is_result_prop( view, name )) return WBEM_E_NOT_FOUND;
1186 table = view->table[table_index];
1187 hr = get_column_index( table, name, &column );
1188 if (hr != S_OK || is_method( table, column )) return WBEM_E_NOT_FOUND;
1190 row = view->result[result_index];
1191 hr = get_value( table, row, column, &val );
1192 if (hr != S_OK) return hr;
1194 if (type) *type = table->columns[column].type & COL_TYPE_MASK;
1195 if (flavor) *flavor = 0;
1197 if (!ret) return S_OK;
1199 vartype = to_vartype( table->columns[column].type & CIM_TYPE_MASK );
1200 if (table->columns[column].type & CIM_FLAG_ARRAY)
1202 CIMTYPE basetype = table->columns[column].type & CIM_TYPE_MASK;
1204 val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
1205 if (!val_ptr) vartype = VT_NULL;
1206 else vartype |= VT_ARRAY;
1207 set_variant( vartype, val, val_ptr, ret );
1208 return S_OK;
1211 switch (table->columns[column].type & COL_TYPE_MASK)
1213 case CIM_STRING:
1214 case CIM_REFERENCE:
1215 case CIM_DATETIME:
1216 if (val)
1218 vartype = VT_BSTR;
1219 val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
1221 else
1222 vartype = VT_NULL;
1223 break;
1224 case CIM_SINT64:
1225 vartype = VT_BSTR;
1226 val_ptr = get_value_bstr( table, row, column );
1227 break;
1228 case CIM_UINT64:
1229 vartype = VT_BSTR;
1230 val_ptr = get_value_bstr( table, row, column );
1231 break;
1232 case CIM_BOOLEAN:
1233 case CIM_SINT8:
1234 case CIM_UINT8:
1235 case CIM_SINT16:
1236 case CIM_UINT16:
1237 case CIM_SINT32:
1238 case CIM_UINT32:
1239 case CIM_REAL32:
1240 break;
1241 default:
1242 ERR("unhandled column type %u\n", table->columns[column].type);
1243 return WBEM_E_FAILED;
1246 set_variant( vartype, val, val_ptr, ret );
1247 return S_OK;
1250 static CIMTYPE to_cimtype( VARTYPE type )
1252 switch (type)
1254 case VT_BOOL: return CIM_BOOLEAN;
1255 case VT_BSTR: return CIM_STRING;
1256 case VT_I1: return CIM_SINT8;
1257 case VT_UI1: return CIM_UINT8;
1258 case VT_I2: return CIM_SINT16;
1259 case VT_UI2: return CIM_UINT16;
1260 case VT_I4: return CIM_SINT32;
1261 case VT_UI4: return CIM_UINT32;
1262 case VT_I8: return CIM_SINT64;
1263 case VT_UI8: return CIM_UINT64;
1264 default:
1265 ERR("unhandled type %u\n", type);
1266 break;
1268 return 0;
1271 static struct array *to_array( VARIANT *var, CIMTYPE *type )
1273 struct array *ret;
1274 LONG bound, i;
1275 VARTYPE vartype;
1276 CIMTYPE basetype;
1278 if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
1279 if (!(basetype = to_cimtype( vartype ))) return NULL;
1280 if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
1281 if (!(ret = malloc( sizeof(struct array) ))) return NULL;
1283 ret->count = bound + 1;
1284 ret->elem_size = get_type_size( basetype );
1285 if (!(ret->ptr = calloc( ret->count, ret->elem_size )))
1287 free( ret );
1288 return NULL;
1290 for (i = 0; i < ret->count; i++)
1292 void *ptr = (char *)ret->ptr + i * ret->elem_size;
1293 if (vartype == VT_BSTR)
1295 BSTR str;
1296 if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
1298 destroy_array( ret, basetype );
1299 return NULL;
1301 *(WCHAR **)ptr = wcsdup( str );
1302 SysFreeString( str );
1303 if (!*(WCHAR **)ptr)
1305 destroy_array( ret, basetype );
1306 return NULL;
1309 else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
1311 destroy_array( ret, basetype );
1312 return NULL;
1315 *type = basetype | CIM_FLAG_ARRAY;
1316 return ret;
1319 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
1321 if (!var)
1323 *val = 0;
1324 return S_OK;
1326 if (V_VT( var ) & VT_ARRAY)
1328 *val = (INT_PTR)to_array( var, type );
1329 if (!*val) return E_OUTOFMEMORY;
1330 return S_OK;
1332 switch (V_VT( var ))
1334 case VT_BOOL:
1335 *val = V_BOOL( var );
1336 *type = CIM_BOOLEAN;
1337 break;
1338 case VT_BSTR:
1339 *val = (INT_PTR)wcsdup( V_BSTR( var ) );
1340 if (!*val) return E_OUTOFMEMORY;
1341 *type = CIM_STRING;
1342 break;
1343 case VT_I2:
1344 *val = V_I2( var );
1345 *type = CIM_SINT16;
1346 break;
1347 case VT_UI2:
1348 *val = V_UI2( var );
1349 *type = CIM_UINT16;
1350 break;
1351 case VT_I4:
1352 *val = V_I4( var );
1353 *type = CIM_SINT32;
1354 break;
1355 case VT_UI4:
1356 *val = V_UI4( var );
1357 *type = CIM_UINT32;
1358 break;
1359 case VT_NULL:
1360 *val = 0;
1361 break;
1362 default:
1363 ERR("unhandled type %u\n", V_VT( var ));
1364 return WBEM_E_FAILED;
1366 return S_OK;
1369 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
1371 HRESULT hr;
1372 UINT row, column, table_index, result_index;
1373 struct table *table;
1374 LONGLONG val;
1376 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1378 table = view->table[table_index];
1379 hr = get_column_index( table, name, &column );
1380 if (hr != S_OK)
1382 FIXME("no support for creating new properties\n");
1383 return WBEM_E_FAILED;
1385 if (is_method( table, column ) || !(table->columns[column].type & COL_FLAG_DYNAMIC))
1386 return WBEM_E_FAILED;
1388 hr = to_longlong( var, &val, &type );
1389 if (hr != S_OK) return hr;
1391 row = view->result[result_index];
1392 return set_value( table, row, column, val, type );
1395 HRESULT get_properties( const struct view *view, UINT index, LONG flags, SAFEARRAY **props )
1397 static const WCHAR * const system_props[] =
1398 { L"__GENUS", L"__CLASS", L"__RELPATH", L"__PROPERTY_COUNT", L"__DERIVATION", L"__SERVER", L"__NAMESPACE",
1399 L"__PATH" };
1400 SAFEARRAY *sa;
1401 BSTR str;
1402 UINT i, table_index, result_index, count = 0;
1403 struct table *table;
1404 HRESULT hr;
1405 LONG j = 0;
1407 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
1408 table = view->table[table_index];
1410 if (!(flags & WBEM_FLAG_NONSYSTEM_ONLY)) count += ARRAY_SIZE(system_props);
1411 if (!(flags & WBEM_FLAG_SYSTEM_ONLY))
1413 for (i = 0; i < table->num_cols; i++)
1415 if (!is_method( table, i ) && is_result_prop( view, table->columns[i].name )) count++;
1419 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, count ))) return E_OUTOFMEMORY;
1421 if (!(flags & WBEM_FLAG_NONSYSTEM_ONLY))
1423 for (j = 0; j < ARRAY_SIZE(system_props); j++)
1425 str = SysAllocString( system_props[j] );
1426 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1428 SysFreeString( str );
1429 SafeArrayDestroy( sa );
1430 return E_OUTOFMEMORY;
1432 SysFreeString( str );
1435 if (!(flags & WBEM_FLAG_SYSTEM_ONLY))
1437 for (i = 0; i < table->num_cols; i++)
1439 if (is_method( table, i ) || !is_result_prop( view, table->columns[i].name )) continue;
1441 str = SysAllocString( table->columns[i].name );
1442 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1444 SysFreeString( str );
1445 SafeArrayDestroy( sa );
1446 return E_OUTOFMEMORY;
1448 SysFreeString( str );
1449 j++;
1453 *props = sa;
1454 return S_OK;