[WBEMPROX] Sync with Wine Staging 1.9.4. CORE-10912
[reactos.git] / reactos / dll / win32 / wbemprox / query.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 #include "wbemprox_private.h"
20
21 #include <winuser.h>
22
23 HRESULT create_view( const struct property *proplist, const WCHAR *class,
24 const struct expr *cond, struct view **ret )
25 {
26 struct view *view = heap_alloc( sizeof(struct view) );
27
28 if (!view) return E_OUTOFMEMORY;
29 view->proplist = proplist;
30 view->table = grab_table( class );
31 view->cond = cond;
32 view->result = NULL;
33 view->count = 0;
34 *ret = view;
35 return S_OK;
36 }
37
38 void destroy_view( struct view *view )
39 {
40 if (!view) return;
41 if (view->table) release_table( view->table );
42 heap_free( view->result );
43 heap_free( view );
44 }
45
46 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
47 {
48 const WCHAR *p = lstr, *q = rstr;
49
50 while (*p && *q)
51 {
52 if (*q == '%')
53 {
54 while (*q == '%') q++;
55 if (!*q) return TRUE;
56 while (*p && *q && toupperW( *p ) == toupperW( *q )) { p++; q++; };
57 if (!*p && !*q) return TRUE;
58 }
59 if (*q != '%' && toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
60 }
61 return TRUE;
62 }
63
64 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
65 {
66 if (!lstr || !rstr)
67 {
68 *val = 0;
69 return S_OK;
70 }
71 switch (op)
72 {
73 case OP_EQ:
74 *val = !strcmpW( lstr, rstr );
75 break;
76 case OP_GT:
77 *val = strcmpW( lstr, rstr ) > 0;
78 break;
79 case OP_LT:
80 *val = strcmpW( lstr, rstr ) < 0;
81 break;
82 case OP_LE:
83 *val = strcmpW( lstr, rstr ) <= 0;
84 break;
85 case OP_GE:
86 *val = strcmpW( lstr, rstr ) >= 0;
87 break;
88 case OP_NE:
89 *val = strcmpW( lstr, rstr );
90 break;
91 case OP_LIKE:
92 *val = eval_like( lstr, rstr );
93 break;
94 default:
95 ERR("unhandled operator %u\n", op);
96 return WBEM_E_INVALID_QUERY;
97 }
98 return S_OK;
99 }
100
101 static BOOL is_int( CIMTYPE type )
102 {
103 switch (type)
104 {
105 case CIM_SINT8:
106 case CIM_SINT16:
107 case CIM_SINT32:
108 case CIM_SINT64:
109 case CIM_UINT8:
110 case CIM_UINT16:
111 case CIM_UINT32:
112 case CIM_UINT64:
113 return TRUE;
114 default:
115 return FALSE;
116 }
117 }
118
119 static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
120 {
121 if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL &&
122 expr->right->type == EXPR_SVAL) return TRUE;
123 else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL &&
124 expr->left->type == EXPR_SVAL) return TRUE;
125 return FALSE;
126 }
127
128 static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype )
129 {
130 if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL &&
131 (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE;
132 else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL &&
133 (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE;
134 return FALSE;
135 }
136
137 static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val )
138 {
139 static const WCHAR trueW[] = {'T','r','u','e',0};
140
141 if (ltype == CIM_STRING) lval = !strcmpiW( (const WCHAR *)(INT_PTR)lval, trueW ) ? -1 : 0;
142 else if (rtype == CIM_STRING) rval = !strcmpiW( (const WCHAR *)(INT_PTR)rval, trueW ) ? -1 : 0;
143
144 switch (op)
145 {
146 case OP_EQ:
147 *val = (lval == rval);
148 break;
149 case OP_NE:
150 *val = (lval != rval);
151 break;
152 default:
153 ERR("unhandled operator %u\n", op);
154 return WBEM_E_INVALID_QUERY;
155 }
156 return S_OK;
157 }
158
159 static UINT resolve_type( UINT left, UINT right )
160 {
161 switch (left)
162 {
163 case CIM_SINT8:
164 case CIM_SINT16:
165 case CIM_SINT32:
166 case CIM_SINT64:
167 case CIM_UINT8:
168 case CIM_UINT16:
169 case CIM_UINT32:
170 case CIM_UINT64:
171 switch (right)
172 {
173 case CIM_SINT8:
174 case CIM_SINT16:
175 case CIM_SINT32:
176 case CIM_SINT64:
177 case CIM_UINT8:
178 case CIM_UINT16:
179 case CIM_UINT32:
180 case CIM_UINT64:
181 return CIM_UINT64;
182 default: break;
183 }
184 break;
185
186 case CIM_STRING:
187 if (right == CIM_STRING) return CIM_STRING;
188 break;
189
190 case CIM_BOOLEAN:
191 if (right == CIM_BOOLEAN) return CIM_BOOLEAN;
192 break;
193
194 default:
195 break;
196 }
197 return CIM_ILLEGAL;
198 }
199
200 static const WCHAR *format_int( WCHAR *buf, CIMTYPE type, LONGLONG val )
201 {
202 static const WCHAR fmt_signedW[] = {'%','d',0};
203 static const WCHAR fmt_unsignedW[] = {'%','u',0};
204 static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
205 static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
206
207 switch (type)
208 {
209 case CIM_SINT8:
210 case CIM_SINT16:
211 case CIM_SINT32:
212 sprintfW( buf, fmt_signedW, val );
213 return buf;
214
215 case CIM_UINT8:
216 case CIM_UINT16:
217 case CIM_UINT32:
218 sprintfW( buf, fmt_unsignedW, val );
219 return buf;
220
221 case CIM_SINT64:
222 wsprintfW( buf, fmt_signed64W, val );
223 return buf;
224
225 case CIM_UINT64:
226 wsprintfW( buf, fmt_unsigned64W, val );
227 return buf;
228
229 default:
230 ERR( "unhandled type %u\n", type );
231 return NULL;
232 }
233 }
234
235 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
236 LONGLONG *val, UINT *type )
237 {
238 HRESULT lret, rret;
239 LONGLONG lval, rval;
240 UINT ltype, rtype;
241
242 lret = eval_cond( table, row, expr->left, &lval, &ltype );
243 rret = eval_cond( table, row, expr->right, &rval, &rtype );
244 if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
245
246 *type = resolve_type( ltype, rtype );
247
248 if (is_boolcmp( expr, ltype, rtype ))
249 return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val );
250
251 if (is_strcmp( expr, ltype, rtype ))
252 {
253 const WCHAR *lstr, *rstr;
254 WCHAR lbuf[21], rbuf[21];
255
256 if (is_int( ltype )) lstr = format_int( lbuf, ltype, lval );
257 else lstr = (const WCHAR *)(INT_PTR)lval;
258
259 if (is_int( rtype )) rstr = format_int( rbuf, rtype, rval );
260 else rstr = (const WCHAR *)(INT_PTR)rval;
261
262 return eval_strcmp( expr->op, lstr, rstr, val );
263 }
264 switch (expr->op)
265 {
266 case OP_EQ:
267 *val = (lval == rval);
268 break;
269 case OP_AND:
270 *val = (lval && rval);
271 break;
272 case OP_OR:
273 *val = (lval || rval);
274 break;
275 case OP_GT:
276 *val = (lval > rval);
277 break;
278 case OP_LT:
279 *val = (lval < rval);
280 break;
281 case OP_LE:
282 *val = (lval <= rval);
283 break;
284 case OP_GE:
285 *val = (lval >= rval);
286 break;
287 case OP_NE:
288 *val = (lval != rval);
289 break;
290 default:
291 ERR("unhandled operator %u\n", expr->op);
292 return WBEM_E_INVALID_QUERY;
293 }
294 return S_OK;
295 }
296
297 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
298 LONGLONG *val, UINT *type )
299
300 {
301 HRESULT hr;
302 UINT column;
303 LONGLONG lval;
304
305 if (expr->op == OP_NOT)
306 {
307 hr = eval_cond( table, row, expr->left, &lval, type );
308 if (hr != S_OK)
309 return hr;
310 *val = !lval;
311 return S_OK;
312 }
313
314 hr = get_column_index( table, expr->left->u.propval->name, &column );
315 if (hr != S_OK)
316 return hr;
317
318 hr = get_value( table, row, column, &lval );
319 if (hr != S_OK)
320 return hr;
321
322 switch (expr->op)
323 {
324 case OP_ISNULL:
325 *val = !lval;
326 break;
327 case OP_NOTNULL:
328 *val = lval;
329 break;
330 default:
331 ERR("unknown operator %u\n", expr->op);
332 return WBEM_E_INVALID_QUERY;
333 }
334
335 *type = table->columns[column].type & CIM_TYPE_MASK;
336 return S_OK;
337 }
338
339 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
340 LONGLONG *val, UINT *type )
341
342 {
343 HRESULT hr;
344 UINT column;
345
346 hr = get_column_index( table, propval->name, &column );
347 if (hr != S_OK)
348 return hr;
349
350 *type = table->columns[column].type & CIM_TYPE_MASK;
351 return get_value( table, row, column, val );
352 }
353
354 HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type )
355 {
356 if (!cond)
357 {
358 *val = 1;
359 *type = CIM_UINT64;
360 return S_OK;
361 }
362 switch (cond->type)
363 {
364 case EXPR_COMPLEX:
365 return eval_binary( table, row, &cond->u.expr, val, type );
366
367 case EXPR_UNARY:
368 return eval_unary( table, row, &cond->u.expr, val, type );
369
370 case EXPR_PROPVAL:
371 return eval_propval( table, row, cond->u.propval, val, type );
372
373 case EXPR_SVAL:
374 *val = (INT_PTR)cond->u.sval;
375 *type = CIM_STRING;
376 return S_OK;
377
378 case EXPR_IVAL:
379 *val = cond->u.ival;
380 *type = CIM_UINT64;
381 return S_OK;
382
383 case EXPR_BVAL:
384 *val = cond->u.ival;
385 *type = CIM_BOOLEAN;
386 return S_OK;
387
388 default:
389 ERR("invalid expression type\n");
390 break;
391 }
392 return WBEM_E_INVALID_QUERY;
393 }
394
395 HRESULT execute_view( struct view *view )
396 {
397 UINT i, j = 0, len;
398
399 if (!view->table) return S_OK;
400 if (view->table->fill)
401 {
402 clear_table( view->table );
403 view->table->fill( view->table, view->cond );
404 }
405 if (!view->table->num_rows) return S_OK;
406
407 len = min( view->table->num_rows, 16 );
408 if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
409
410 for (i = 0; i < view->table->num_rows; i++)
411 {
412 HRESULT hr;
413 LONGLONG val = 0;
414 UINT type;
415
416 if (j >= len)
417 {
418 UINT *tmp;
419 len *= 2;
420 if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
421 view->result = tmp;
422 }
423 if ((hr = eval_cond( view->table, i, view->cond, &val, &type )) != S_OK) return hr;
424 if (val) view->result[j++] = i;
425 }
426 view->count = j;
427 return S_OK;
428 }
429
430 struct query *create_query(void)
431 {
432 struct query *query;
433
434 if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
435 list_init( &query->mem );
436 query->refs = 1;
437 return query;
438 }
439
440 void free_query( struct query *query )
441 {
442 struct list *mem, *next;
443
444 if (!query) return;
445 destroy_view( query->view );
446 LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { heap_free( mem ); }
447 heap_free( query );
448 }
449
450 struct query *addref_query( struct query *query )
451 {
452 InterlockedIncrement( &query->refs );
453 return query;
454 }
455
456 void release_query( struct query *query )
457 {
458 if (!InterlockedDecrement( &query->refs )) free_query( query );
459 }
460
461 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
462 {
463 HRESULT hr;
464 struct query *query;
465
466 *result = NULL;
467 if (!(query = create_query())) return E_OUTOFMEMORY;
468 hr = parse_query( str, &query->view, &query->mem );
469 if (hr != S_OK) goto done;
470 hr = execute_view( query->view );
471 if (hr != S_OK) goto done;
472 hr = EnumWbemClassObject_create( query, (void **)result );
473
474 done:
475 release_query( query );
476 return hr;
477 }
478
479 BOOL is_selected_prop( const struct view *view, const WCHAR *name )
480 {
481 const struct property *prop = view->proplist;
482
483 if (!prop) return TRUE;
484 while (prop)
485 {
486 if (!strcmpiW( prop->name, name )) return TRUE;
487 prop = prop->next;
488 }
489 return FALSE;
490 }
491
492 static BOOL is_system_prop( const WCHAR *name )
493 {
494 return (name[0] == '_' && name[1] == '_');
495 }
496
497 static BSTR build_servername( const struct view *view )
498 {
499 WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
500 DWORD len = sizeof(server)/sizeof(server[0]);
501
502 if (view->proplist) return NULL;
503
504 if (!(GetComputerNameW( server, &len ))) return NULL;
505 for (p = server; *p; p++) *p = toupperW( *p );
506 return SysAllocString( server );
507 }
508
509 static BSTR build_classname( const struct view *view )
510 {
511 return SysAllocString( view->table->name );
512 }
513
514 static BSTR build_namespace( const struct view *view )
515 {
516 static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
517
518 if (view->proplist) return NULL;
519 return SysAllocString( cimv2W );
520 }
521
522 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
523 {
524 static const WCHAR fmtW[] = {'%','s','=','%','s',0};
525 UINT i, j, offset, row = view->result[index];
526 BSTR *values, ret = NULL;
527
528 if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
529
530 *len = j = 0;
531 for (i = 0; i < view->table->num_cols; i++)
532 {
533 if (view->table->columns[i].type & COL_FLAG_KEY)
534 {
535 const WCHAR *name = view->table->columns[i].name;
536
537 values[j] = get_value_bstr( view->table, row, i );
538 *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
539 j++;
540 }
541 }
542 if ((ret = SysAllocStringLen( NULL, *len )))
543 {
544 offset = j = 0;
545 for (i = 0; i < view->table->num_cols; i++)
546 {
547 if (view->table->columns[i].type & COL_FLAG_KEY)
548 {
549 const WCHAR *name = view->table->columns[i].name;
550
551 offset += sprintfW( ret + offset, fmtW, name, values[j] );
552 if (j < count - 1) ret[offset++] = ',';
553 j++;
554 }
555 }
556 }
557 for (i = 0; i < count; i++) SysFreeString( values[i] );
558 heap_free( values );
559 return ret;
560 }
561
562 static UINT count_key_columns( const struct view *view )
563 {
564 UINT i, num_keys = 0;
565
566 for (i = 0; i < view->table->num_cols; i++)
567 {
568 if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
569 }
570 return num_keys;
571 }
572
573 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
574 {
575 static const WCHAR fmtW[] = {'%','s','.','%','s',0};
576 BSTR class, proplist, ret = NULL;
577 UINT num_keys, len;
578
579 if (view->proplist) return NULL;
580
581 if (!(class = build_classname( view ))) return NULL;
582 if (!(num_keys = count_key_columns( view ))) return class;
583 if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
584
585 len += strlenW( fmtW ) + SysStringLen( class );
586 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
587 sprintfW( ret, fmtW, class, proplist );
588
589 done:
590 SysFreeString( class );
591 SysFreeString( proplist );
592 return ret;
593 }
594
595 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
596 {
597 static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
598 BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
599 UINT len;
600
601 if (view->proplist) return NULL;
602
603 if (!(server = build_servername( view ))) return NULL;
604 if (!(namespace = build_namespace( view ))) goto done;
605 if (!(relpath = build_relpath( view, index, name ))) goto done;
606
607 len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
608 if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
609 sprintfW( ret, fmtW, server, namespace, relpath );
610
611 done:
612 SysFreeString( server );
613 SysFreeString( namespace );
614 SysFreeString( relpath );
615 return ret;
616 }
617
618 BOOL is_method( const struct table *table, UINT column )
619 {
620 return table->columns[column].type & COL_FLAG_METHOD;
621 }
622
623 static UINT count_properties( const struct view *view )
624 {
625 UINT i, num_props = 0;
626
627 for (i = 0; i < view->table->num_cols; i++)
628 {
629 if (!is_method( view->table, i)) num_props++;
630 }
631 return num_props;
632 }
633
634 static UINT count_selected_properties( const struct view *view )
635 {
636 const struct property *prop = view->proplist;
637 UINT count;
638
639 if (!prop) return count_properties( view );
640
641 count = 1;
642 while ((prop = prop->next)) count++;
643 return count;
644 }
645
646 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
647 VARIANT *ret, CIMTYPE *type, LONG *flavor )
648 {
649 static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
650 static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
651 static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
652 static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
653 static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
654 static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
655 static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
656
657 if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
658
659 if (!strcmpiW( name, classW ))
660 {
661 V_VT( ret ) = VT_BSTR;
662 V_BSTR( ret ) = build_classname( view );
663 if (type) *type = CIM_STRING;
664 return S_OK;
665 }
666 if (!strcmpiW( name, genusW ))
667 {
668 V_VT( ret ) = VT_I4;
669 V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
670 if (type) *type = CIM_SINT32;
671 return S_OK;
672 }
673 else if (!strcmpiW( name, namespaceW ))
674 {
675 V_VT( ret ) = VT_BSTR;
676 V_BSTR( ret ) = build_namespace( view );
677 if (type) *type = CIM_STRING;
678 return S_OK;
679 }
680 else if (!strcmpiW( name, pathW ))
681 {
682 V_VT( ret ) = VT_BSTR;
683 V_BSTR( ret ) = build_path( view, index, name );
684 if (type) *type = CIM_STRING;
685 return S_OK;
686 }
687 if (!strcmpiW( name, propcountW ))
688 {
689 V_VT( ret ) = VT_I4;
690 V_I4( ret ) = count_selected_properties( view );
691 if (type) *type = CIM_SINT32;
692 return S_OK;
693 }
694 else if (!strcmpiW( name, relpathW ))
695 {
696 V_VT( ret ) = VT_BSTR;
697 V_BSTR( ret ) = build_relpath( view, index, name );
698 if (type) *type = CIM_STRING;
699 return S_OK;
700 }
701 else if (!strcmpiW( name, serverW ))
702 {
703 V_VT( ret ) = VT_BSTR;
704 V_BSTR( ret ) = build_servername( view );
705 if (type) *type = CIM_STRING;
706 return S_OK;
707 }
708 FIXME("system property %s not implemented\n", debugstr_w(name));
709 return WBEM_E_NOT_FOUND;
710 }
711
712 VARTYPE to_vartype( CIMTYPE type )
713 {
714 switch (type)
715 {
716 case CIM_BOOLEAN: return VT_BOOL;
717 case CIM_STRING:
718 case CIM_DATETIME: return VT_BSTR;
719 case CIM_SINT8: return VT_I1;
720 case CIM_UINT8: return VT_UI1;
721 case CIM_SINT16: return VT_I2;
722 case CIM_UINT16: return VT_UI2;
723 case CIM_SINT32: return VT_I4;
724 case CIM_UINT32: return VT_UI4;
725 case CIM_SINT64: return VT_I8;
726 case CIM_UINT64: return VT_UI8;
727 default:
728 ERR("unhandled type %u\n", type);
729 break;
730 }
731 return 0;
732 }
733
734 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
735 {
736 SAFEARRAY *ret;
737 UINT size = get_type_size( type );
738 VARTYPE vartype = to_vartype( type );
739 LONG i;
740
741 if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
742
743 for (i = 0; i < array->count; i++)
744 {
745 void *ptr = (char *)array->ptr + i * size;
746 if (vartype == VT_BSTR)
747 {
748 BSTR str = SysAllocString( *(const WCHAR **)ptr );
749 if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
750 {
751 SysFreeString( str );
752 SafeArrayDestroy( ret );
753 return NULL;
754 }
755 SysFreeString( str );
756 }
757 else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
758 {
759 SafeArrayDestroy( ret );
760 return NULL;
761 }
762 }
763 return ret;
764 }
765
766 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
767 {
768 if (type & VT_ARRAY)
769 {
770 V_VT( ret ) = type;
771 V_ARRAY( ret ) = val_ptr;
772 return;
773 }
774 switch (type)
775 {
776 case VT_BOOL:
777 V_BOOL( ret ) = val;
778 break;
779 case VT_BSTR:
780 V_BSTR( ret ) = val_ptr;
781 break;
782 case VT_I1:
783 V_I1( ret ) = val;
784 break;
785 case VT_UI1:
786 V_UI1( ret ) = val;
787 break;
788 case VT_I2:
789 V_I2( ret ) = val;
790 break;
791 case VT_UI2:
792 V_UI2( ret ) = val;
793 break;
794 case VT_I4:
795 V_I4( ret ) = val;
796 break;
797 case VT_UI4:
798 V_UI4( ret ) = val;
799 break;
800 case VT_NULL:
801 break;
802 default:
803 ERR("unhandled variant type %u\n", type);
804 return;
805 }
806 V_VT( ret ) = type;
807 }
808
809 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
810 CIMTYPE *type, LONG *flavor )
811 {
812 HRESULT hr;
813 UINT column, row;
814 VARTYPE vartype;
815 void *val_ptr = NULL;
816 LONGLONG val;
817
818 if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
819 if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
820
821 hr = get_column_index( view->table, name, &column );
822 if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
823
824 row = view->result[index];
825 hr = get_value( view->table, row, column, &val );
826 if (hr != S_OK) return hr;
827
828 vartype = view->table->columns[column].vartype;
829 if (view->table->columns[column].type & CIM_FLAG_ARRAY)
830 {
831 CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
832
833 val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
834 if (!val_ptr) vartype = VT_NULL;
835 else if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
836 goto done;
837 }
838 switch (view->table->columns[column].type & COL_TYPE_MASK)
839 {
840 case CIM_BOOLEAN:
841 if (!vartype) vartype = VT_BOOL;
842 break;
843 case CIM_STRING:
844 case CIM_DATETIME:
845 if (val)
846 {
847 vartype = VT_BSTR;
848 val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
849 }
850 else
851 vartype = VT_NULL;
852 break;
853 case CIM_SINT8:
854 if (!vartype) vartype = VT_I1;
855 break;
856 case CIM_UINT8:
857 if (!vartype) vartype = VT_UI1;
858 break;
859 case CIM_SINT16:
860 if (!vartype) vartype = VT_I2;
861 break;
862 case CIM_UINT16:
863 if (!vartype) vartype = VT_UI2;
864 break;
865 case CIM_SINT32:
866 if (!vartype) vartype = VT_I4;
867 break;
868 case CIM_UINT32:
869 if (!vartype) vartype = VT_UI4;
870 break;
871 case CIM_SINT64:
872 vartype = VT_BSTR;
873 val_ptr = get_value_bstr( view->table, row, column );
874 break;
875 case CIM_UINT64:
876 vartype = VT_BSTR;
877 val_ptr = get_value_bstr( view->table, row, column );
878 break;
879 default:
880 ERR("unhandled column type %u\n", view->table->columns[column].type);
881 return WBEM_E_FAILED;
882 }
883
884 done:
885 set_variant( vartype, val, val_ptr, ret );
886 if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
887 if (flavor) *flavor = 0;
888 return S_OK;
889 }
890
891 static CIMTYPE to_cimtype( VARTYPE type )
892 {
893 switch (type)
894 {
895 case VT_BOOL: return CIM_BOOLEAN;
896 case VT_BSTR: return CIM_STRING;
897 case VT_I1: return CIM_SINT8;
898 case VT_UI1: return CIM_UINT8;
899 case VT_I2: return CIM_SINT16;
900 case VT_UI2: return CIM_UINT16;
901 case VT_I4: return CIM_SINT32;
902 case VT_UI4: return CIM_UINT32;
903 case VT_I8: return CIM_SINT64;
904 case VT_UI8: return CIM_UINT64;
905 default:
906 ERR("unhandled type %u\n", type);
907 break;
908 }
909 return 0;
910 }
911
912 static struct array *to_array( VARIANT *var, CIMTYPE *type )
913 {
914 struct array *ret;
915 LONG bound, i;
916 VARTYPE vartype;
917 CIMTYPE basetype;
918 UINT size;
919
920 if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
921 if (!(basetype = to_cimtype( vartype ))) return NULL;
922 if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
923 if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
924
925 ret->count = bound + 1;
926 size = get_type_size( basetype );
927 if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
928 {
929 heap_free( ret );
930 return NULL;
931 }
932 for (i = 0; i < ret->count; i++)
933 {
934 void *ptr = (char *)ret->ptr + i * size;
935 if (vartype == VT_BSTR)
936 {
937 BSTR str;
938 if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
939 {
940 destroy_array( ret, basetype );
941 return NULL;
942 }
943 *(WCHAR **)ptr = heap_strdupW( str );
944 SysFreeString( str );
945 if (!*(WCHAR **)ptr)
946 {
947 destroy_array( ret, basetype );
948 return NULL;
949 }
950 }
951 else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
952 {
953 destroy_array( ret, basetype );
954 return NULL;
955 }
956 }
957 *type = basetype | CIM_FLAG_ARRAY;
958 return ret;
959 }
960
961 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
962 {
963 if (!var)
964 {
965 *val = 0;
966 return S_OK;
967 }
968 if (V_VT( var ) & VT_ARRAY)
969 {
970 *val = (INT_PTR)to_array( var, type );
971 if (!*val) return E_OUTOFMEMORY;
972 return S_OK;
973 }
974 switch (V_VT( var ))
975 {
976 case VT_BOOL:
977 *val = V_BOOL( var );
978 *type = CIM_BOOLEAN;
979 break;
980 case VT_BSTR:
981 *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
982 if (!*val) return E_OUTOFMEMORY;
983 *type = CIM_STRING;
984 break;
985 case VT_I2:
986 *val = V_I2( var );
987 *type = CIM_SINT16;
988 break;
989 case VT_UI2:
990 *val = V_UI2( var );
991 *type = CIM_UINT16;
992 break;
993 case VT_I4:
994 *val = V_I4( var );
995 *type = CIM_SINT32;
996 break;
997 case VT_UI4:
998 *val = V_UI4( var );
999 *type = CIM_UINT32;
1000 break;
1001 case VT_NULL:
1002 *val = 0;
1003 break;
1004 default:
1005 ERR("unhandled type %u\n", V_VT( var ));
1006 return WBEM_E_FAILED;
1007 }
1008 return S_OK;
1009 }
1010
1011 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
1012 {
1013 HRESULT hr;
1014 UINT column, row = view->result[index];
1015 LONGLONG val;
1016
1017 hr = get_column_index( view->table, name, &column );
1018 if (hr != S_OK)
1019 {
1020 FIXME("no support for creating new properties\n");
1021 return WBEM_E_FAILED;
1022 }
1023 if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
1024 return WBEM_E_FAILED;
1025
1026 hr = to_longlong( var, &val, &type );
1027 if (hr != S_OK) return hr;
1028
1029 return set_value( view->table, row, column, val, type );
1030 }
1031
1032 HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
1033 {
1034 SAFEARRAY *sa;
1035 BSTR str;
1036 UINT i, num_props = count_selected_properties( view );
1037 LONG j;
1038
1039 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
1040
1041 for (i = 0, j = 0; i < view->table->num_cols; i++)
1042 {
1043 BOOL is_system;
1044
1045 if (is_method( view->table, i )) continue;
1046 if (!is_selected_prop( view, view->table->columns[i].name )) continue;
1047
1048 is_system = is_system_prop( view->table->columns[i].name );
1049 if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
1050 else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
1051
1052 str = SysAllocString( view->table->columns[i].name );
1053 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
1054 {
1055 SysFreeString( str );
1056 SafeArrayDestroy( sa );
1057 return E_OUTOFMEMORY;
1058 }
1059 SysFreeString( str );
1060 j++;
1061 }
1062 *props = sa;
1063 return S_OK;
1064 }