wbemprox: Add support for enumerating class methods.
[wine] / dlls / wbemprox / table.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 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27
28 #include "wine/debug.h"
29 #include "wbemprox_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 HRESULT get_column_index( const struct table *table, const WCHAR *name, UINT *column )
34 {
35     UINT i;
36     for (i = 0; i < table->num_cols; i++)
37     {
38         if (!strcmpiW( table->columns[i].name, name ))
39         {
40             *column = i;
41             return S_OK;
42         }
43     }
44     return WBEM_E_INVALID_QUERY;
45 }
46
47 UINT get_type_size( CIMTYPE type )
48 {
49     if (type & CIM_FLAG_ARRAY) return sizeof(void *);
50
51     switch (type)
52     {
53     case CIM_BOOLEAN:
54         return sizeof(int);
55     case CIM_SINT16:
56     case CIM_UINT16:
57         return sizeof(INT16);
58     case CIM_SINT32:
59     case CIM_UINT32:
60         return sizeof(INT32);
61     case CIM_SINT64:
62     case CIM_UINT64:
63         return sizeof(INT64);
64     case CIM_DATETIME:
65     case CIM_STRING:
66         return sizeof(WCHAR *);
67     default:
68         ERR("unhandled type %u\n", type);
69         break;
70     }
71     return sizeof(LONGLONG);
72 }
73
74 static UINT get_column_size( const struct table *table, UINT column )
75 {
76     return get_type_size( table->columns[column].type & COL_TYPE_MASK );
77 }
78
79 static UINT get_column_offset( const struct table *table, UINT column )
80 {
81     UINT i, offset = 0;
82     for (i = 0; i < column; i++) offset += get_column_size( table, i );
83     return offset;
84 }
85
86 static UINT get_row_size( const struct table *table )
87 {
88     return get_column_offset( table, table->num_cols - 1 ) + get_column_size( table, table->num_cols - 1 );
89 }
90
91 HRESULT get_value( const struct table *table, UINT row, UINT column, LONGLONG *val )
92 {
93     UINT col_offset, row_size;
94     const BYTE *ptr;
95
96     col_offset = get_column_offset( table, column );
97     row_size = get_row_size( table );
98     ptr = table->data + row * row_size + col_offset;
99
100     if (table->columns[column].type & CIM_FLAG_ARRAY)
101     {
102         *val = (LONGLONG)(INT_PTR)*(const void **)ptr;
103         return S_OK;
104     }
105     switch (table->columns[column].type & COL_TYPE_MASK)
106     {
107     case CIM_BOOLEAN:
108         *val = *(const int *)ptr;
109         break;
110     case CIM_DATETIME:
111     case CIM_STRING:
112         *val = (LONGLONG)(INT_PTR)*(const WCHAR **)ptr;
113         break;
114     case CIM_SINT16:
115         *val = *(const INT16 *)ptr;
116         break;
117     case CIM_UINT16:
118         *val = *(const UINT16 *)ptr;
119         break;
120     case CIM_SINT32:
121         *val = *(const INT32 *)ptr;
122         break;
123     case CIM_UINT32:
124         *val = *(const UINT32 *)ptr;
125         break;
126     case CIM_SINT64:
127         *val = *(const INT64 *)ptr;
128         break;
129     case CIM_UINT64:
130         *val = *(const UINT64 *)ptr;
131         break;
132     default:
133         ERR("invalid column type %u\n", table->columns[column].type & COL_TYPE_MASK);
134         *val = 0;
135         break;
136     }
137     return S_OK;
138 }
139
140 BSTR get_value_bstr( const struct table *table, UINT row, UINT column )
141 {
142     static const WCHAR fmt_signedW[] = {'%','d',0};
143     static const WCHAR fmt_unsignedW[] = {'%','u',0};
144     static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
145     static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
146     static const WCHAR fmt_strW[] = {'\"','%','s','\"',0};
147     LONGLONG val;
148     BSTR ret;
149     WCHAR number[22];
150     UINT len;
151
152     if (table->columns[column].type & CIM_FLAG_ARRAY)
153     {
154         FIXME("array to string conversion not handled\n");
155         return NULL;
156     }
157     if (get_value( table, row, column, &val ) != S_OK) return NULL;
158
159     switch (table->columns[column].type & COL_TYPE_MASK)
160     {
161     case CIM_DATETIME:
162     case CIM_STRING:
163         len = strlenW( (const WCHAR *)(INT_PTR)val ) + 2;
164         if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
165         sprintfW( ret, fmt_strW, (const WCHAR *)(INT_PTR)val );
166         return ret;
167
168     case CIM_SINT16:
169     case CIM_SINT32:
170         sprintfW( number, fmt_signedW, val );
171         return SysAllocString( number );
172
173     case CIM_UINT16:
174     case CIM_UINT32:
175         sprintfW( number, fmt_unsignedW, val );
176         return SysAllocString( number );
177
178     case CIM_SINT64:
179         wsprintfW( number, fmt_signed64W, val );
180         return SysAllocString( number );
181
182     case CIM_UINT64:
183         wsprintfW( number, fmt_unsigned64W, val );
184         return SysAllocString( number );
185
186     default:
187         FIXME("unhandled column type %u\n", table->columns[column].type & COL_TYPE_MASK);
188         break;
189     }
190     return NULL;
191 }
192
193 HRESULT set_value( const struct table *table, UINT row, UINT column, LONGLONG val,
194                    CIMTYPE type )
195 {
196     UINT col_offset, row_size;
197     BYTE *ptr;
198
199     if ((table->columns[column].type & COL_TYPE_MASK) != type) return WBEM_E_TYPE_MISMATCH;
200
201     col_offset = get_column_offset( table, column );
202     row_size = get_row_size( table );
203     ptr = table->data + row * row_size + col_offset;
204
205     switch (table->columns[column].type & COL_TYPE_MASK)
206     {
207     case CIM_DATETIME:
208     case CIM_STRING:
209         *(WCHAR **)ptr = (WCHAR *)(INT_PTR)val;
210         break;
211     case CIM_SINT16:
212         *(INT16 *)ptr = val;
213         break;
214     case CIM_UINT16:
215         *(UINT16 *)ptr = val;
216         break;
217     case CIM_SINT32:
218         *(INT32 *)ptr = val;
219         break;
220     case CIM_UINT32:
221         *(UINT32 *)ptr = val;
222         break;
223     case CIM_SINT64:
224         *(INT64 *)ptr = val;
225         break;
226     case CIM_UINT64:
227         *(UINT64 *)ptr = val;
228         break;
229     default:
230         FIXME("unhandled column type %u\n", type);
231         return WBEM_E_FAILED;
232     }
233     return S_OK;
234 }
235
236 static void clear_table( struct table *table )
237 {
238     UINT i, j, type;
239     LONGLONG val;
240
241     if (!table->data) return;
242
243     for (i = 0; i < table->num_rows; i++)
244     {
245         for (j = 0; j < table->num_cols; j++)
246         {
247             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
248
249             type = table->columns[j].type & COL_TYPE_MASK;
250             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
251             {
252                 if (get_value( table, i, j, &val ) == S_OK) heap_free( (void *)(INT_PTR)val );
253             }
254         }
255     }
256     if (table->fill)
257     {
258         table->num_rows = 0;
259         heap_free( table->data );
260         table->data = NULL;
261     }
262 }
263
264 void free_columns( struct column *columns, UINT num_cols )
265 {
266     UINT i;
267
268     for (i = 0; i < num_cols; i++)
269     {
270         heap_free( (WCHAR *)columns[i].name );
271     }
272     heap_free( columns );
273 }
274
275 void free_table( struct table *table )
276 {
277     if (!table) return;
278
279     clear_table( table );
280     if (table->flags & TABLE_FLAG_DYNAMIC)
281     {
282         heap_free( (WCHAR *)table->name );
283         free_columns( (struct column *)table->columns, table->num_cols );
284         heap_free( table );
285     }
286 }
287
288 struct table *get_table( const WCHAR *name )
289 {
290     struct table *table;
291
292     LIST_FOR_EACH_ENTRY( table, table_list, struct table, entry )
293     {
294         if (!strcmpiW( table->name, name ))
295         {
296             if (table->fill && !table->data) table->fill( table );
297             return table;
298         }
299     }
300     return NULL;
301 }
302
303 struct table *create_table( const WCHAR *name, UINT num_cols, const struct column *columns,
304                             UINT num_rows, BYTE *data, void (*fill)(struct table *) )
305 {
306     struct table *table;
307
308     if (!(table = heap_alloc( sizeof(*table) ))) return NULL;
309     table->name     = name;
310     table->num_cols = num_cols;
311     table->columns  = columns;
312     table->num_rows = num_rows;
313     table->data     = data;
314     table->fill     = fill;
315     table->flags    = TABLE_FLAG_DYNAMIC;
316     return table;
317 }
318
319 BOOL add_table( struct table *table )
320 {
321     struct table *iter;
322
323     LIST_FOR_EACH_ENTRY( iter, table_list, struct table, entry )
324     {
325         if (!strcmpiW( iter->name, table->name ))
326         {
327             TRACE("table %s already exists\n", debugstr_w(table->name));
328             return FALSE;
329         }
330     }
331     list_add_tail( table_list, &table->entry );
332     return TRUE;
333 }
334
335 const WCHAR *get_method_name( const WCHAR *class, UINT index )
336 {
337     struct table *table;
338     UINT i, count = 0;
339
340     if (!(table = get_table( class ))) return NULL;
341
342     for (i = 0; i < table->num_cols; i++)
343     {
344         if (table->columns[i].type & COL_FLAG_METHOD)
345         {
346             if (index == count) return table->columns[i].name;
347             count++;
348         }
349     }
350     return NULL;
351 }