Sync with trunk r63174.
[reactos.git] / 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 && toupperW( p[1] ) != toupperW( q[1] )) p++;
55 if (!*p) return TRUE;
56 }
57 if (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 static 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 static inline 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_SINT16: return VT_I2;
656 case CIM_UINT16: return VT_UI2;
657 case CIM_SINT32: return VT_I4;
658 case CIM_UINT32: return VT_UI4;
659 case CIM_SINT64: return VT_I8;
660 case CIM_UINT64: return VT_UI8;
661 default:
662 ERR("unhandled type %u\n", type);
663 break;
664 }
665 return 0;
666 }
667
668 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
669 {
670 SAFEARRAY *ret;
671 UINT size = get_type_size( type );
672 VARTYPE vartype = to_vartype( type );
673 LONG i;
674
675 if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
676
677 for (i = 0; i < array->count; i++)
678 {
679 void *ptr = (char *)array->ptr + i * size;
680 if (vartype == VT_BSTR)
681 {
682 BSTR str = SysAllocString( *(const WCHAR **)ptr );
683 if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
684 {
685 SysFreeString( str );
686 SafeArrayDestroy( ret );
687 return NULL;
688 }
689 }
690 else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
691 {
692 SafeArrayDestroy( ret );
693 return NULL;
694 }
695 }
696 return ret;
697 }
698
699 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
700 {
701 if (type & VT_ARRAY)
702 {
703 V_VT( ret ) = type;
704 V_ARRAY( ret ) = val_ptr;
705 return;
706 }
707 switch (type)
708 {
709 case VT_BOOL:
710 V_BOOL( ret ) = val;
711 break;
712 case VT_BSTR:
713 V_BSTR( ret ) = val_ptr;
714 break;
715 case VT_I2:
716 V_I2( ret ) = val;
717 break;
718 case VT_UI2:
719 V_UI2( ret ) = val;
720 break;
721 case VT_I4:
722 V_I4( ret ) = val;
723 break;
724 case VT_UI4:
725 V_UI4( ret ) = val;
726 break;
727 case VT_NULL:
728 break;
729 default:
730 ERR("unhandled variant type %u\n", type);
731 return;
732 }
733 V_VT( ret ) = type;
734 }
735
736 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
737 CIMTYPE *type, LONG *flavor )
738 {
739 HRESULT hr;
740 UINT column, row;
741 VARTYPE vartype;
742 void *val_ptr = NULL;
743 LONGLONG val;
744
745 if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
746 if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
747
748 hr = get_column_index( view->table, name, &column );
749 if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
750
751 row = view->result[index];
752 hr = get_value( view->table, row, column, &val );
753 if (hr != S_OK) return hr;
754
755 vartype = view->table->columns[column].vartype;
756 if (view->table->columns[column].type & CIM_FLAG_ARRAY)
757 {
758 CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
759
760 val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
761 if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
762 goto done;
763 }
764 switch (view->table->columns[column].type & COL_TYPE_MASK)
765 {
766 case CIM_BOOLEAN:
767 if (!vartype) vartype = VT_BOOL;
768 break;
769 case CIM_STRING:
770 case CIM_DATETIME:
771 if (val)
772 {
773 vartype = VT_BSTR;
774 val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
775 }
776 else
777 vartype = VT_NULL;
778 break;
779 case CIM_SINT16:
780 if (!vartype) vartype = VT_I2;
781 break;
782 case CIM_UINT16:
783 if (!vartype) vartype = VT_UI2;
784 break;
785 case CIM_SINT32:
786 if (!vartype) vartype = VT_I4;
787 break;
788 case CIM_UINT32:
789 if (!vartype) vartype = VT_UI4;
790 break;
791 case CIM_SINT64:
792 vartype = VT_BSTR;
793 val_ptr = get_value_bstr( view->table, row, column );
794 break;
795 case CIM_UINT64:
796 vartype = VT_BSTR;
797 val_ptr = get_value_bstr( view->table, row, column );
798 break;
799 default:
800 ERR("unhandled column type %u\n", view->table->columns[column].type);
801 return WBEM_E_FAILED;
802 }
803
804 done:
805 set_variant( vartype, val, val_ptr, ret );
806 if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
807 if (flavor) *flavor = 0;
808 return S_OK;
809 }
810
811 static CIMTYPE to_cimtype( VARTYPE type )
812 {
813 switch (type)
814 {
815 case VT_BOOL: return CIM_BOOLEAN;
816 case VT_BSTR: return CIM_STRING;
817 case VT_I2: return CIM_SINT16;
818 case VT_UI2: return CIM_UINT16;
819 case VT_I4: return CIM_SINT32;
820 case VT_UI4: return CIM_UINT32;
821 case VT_I8: return CIM_SINT64;
822 case VT_UI8: return CIM_UINT64;
823 default:
824 ERR("unhandled type %u\n", type);
825 break;
826 }
827 return 0;
828 }
829
830 static struct array *to_array( VARIANT *var, CIMTYPE *type )
831 {
832 struct array *ret;
833 LONG bound, i;
834 VARTYPE vartype;
835 CIMTYPE basetype;
836 UINT size;
837
838 if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
839 if (!(basetype = to_cimtype( vartype ))) return NULL;
840 if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
841 if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
842
843 ret->count = bound + 1;
844 size = get_type_size( basetype );
845 if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
846 {
847 heap_free( ret );
848 return NULL;
849 }
850 for (i = 0; i < ret->count; i++)
851 {
852 void *ptr = (char *)ret->ptr + i * size;
853 if (vartype == VT_BSTR)
854 {
855 BSTR str;
856 if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
857 {
858 destroy_array( ret, basetype );
859 return NULL;
860 }
861 *(WCHAR **)ptr = heap_strdupW( str );
862 SysFreeString( str );
863 if (!*(WCHAR **)ptr)
864 {
865 destroy_array( ret, basetype );
866 return NULL;
867 }
868 }
869 else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
870 {
871 destroy_array( ret, basetype );
872 return NULL;
873 }
874 }
875 *type = basetype | CIM_FLAG_ARRAY;
876 return ret;
877 }
878
879 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
880 {
881 if (!var)
882 {
883 *val = 0;
884 return S_OK;
885 }
886 if (V_VT( var ) & VT_ARRAY)
887 {
888 *val = (INT_PTR)to_array( var, type );
889 if (!*val) return E_OUTOFMEMORY;
890 return S_OK;
891 }
892 switch (V_VT( var ))
893 {
894 case VT_BOOL:
895 *val = V_BOOL( var );
896 *type = CIM_BOOLEAN;
897 break;
898 case VT_BSTR:
899 *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
900 if (!*val) return E_OUTOFMEMORY;
901 *type = CIM_STRING;
902 break;
903 case VT_I2:
904 *val = V_I2( var );
905 *type = CIM_SINT16;
906 break;
907 case VT_UI2:
908 *val = V_UI2( var );
909 *type = CIM_UINT16;
910 break;
911 case VT_I4:
912 *val = V_I4( var );
913 *type = CIM_SINT32;
914 break;
915 case VT_UI4:
916 *val = V_UI4( var );
917 *type = CIM_UINT32;
918 break;
919 case VT_NULL:
920 *val = 0;
921 break;
922 default:
923 ERR("unhandled type %u\n", V_VT( var ));
924 return WBEM_E_FAILED;
925 }
926 return S_OK;
927 }
928
929 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
930 {
931 HRESULT hr;
932 UINT column, row = view->result[index];
933 LONGLONG val;
934
935 hr = get_column_index( view->table, name, &column );
936 if (hr != S_OK)
937 {
938 FIXME("no support for creating new properties\n");
939 return WBEM_E_FAILED;
940 }
941 if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
942 return WBEM_E_FAILED;
943
944 hr = to_longlong( var, &val, &type );
945 if (hr != S_OK) return hr;
946
947 return set_value( view->table, row, column, val, type );
948 }
949
950 HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
951 {
952 SAFEARRAY *sa;
953 BSTR str;
954 LONG i;
955 UINT num_props = count_properties( view );
956
957 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
958
959 for (i = 0; i < view->table->num_cols; i++)
960 {
961 BOOL is_system;
962
963 if (is_method( view->table, i )) continue;
964
965 is_system = is_system_prop( view->table->columns[i].name );
966 if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
967 else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
968
969 str = SysAllocString( view->table->columns[i].name );
970 if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
971 {
972 SysFreeString( str );
973 SafeArrayDestroy( sa );
974 return E_OUTOFMEMORY;
975 }
976 }
977 *props = sa;
978 return S_OK;
979 }