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