If using the default values, also set dwType to REG_SZ as our default
[wine] / dlls / msi / record.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "msi.h"
29 #include "msiquery.h"
30 #include "msipriv.h"
31 #include "objidl.h"
32 #include "winnls.h"
33
34 #include "query.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msi);
37
38 #define MSIFIELD_NULL   0
39 #define MSIFIELD_INT    1
40 #define MSIFIELD_STR    2
41 #define MSIFIELD_WSTR   3
42 #define MSIFIELD_STREAM 4
43
44 /* maybe we can use a Variant instead of doing it ourselves? */
45 typedef struct tagMSIFIELD
46 {
47     UINT type;
48     union
49     {
50         INT iVal;
51         LPSTR szVal;
52         LPWSTR szwVal;
53         IStream *stream;
54     } u;
55 } MSIFIELD;
56
57 typedef struct tagMSIRECORD
58 {
59     UINT count;       /* as passed to MsiCreateRecord */
60     MSIFIELD fields[1]; /* nb. array size is count+1 */
61 } MSIRECORD;
62
63 void MSI_FreeField( MSIFIELD *field )
64 {
65     switch( field->type )
66     {
67     case MSIFIELD_NULL:
68     case MSIFIELD_INT:
69         break;
70     case MSIFIELD_STR:
71         HeapFree( GetProcessHeap(), 0, field->u.szVal);
72         break;
73     case MSIFIELD_WSTR:
74         HeapFree( GetProcessHeap(), 0, field->u.szwVal);
75         break;
76     case MSIFIELD_STREAM:
77         IStream_Release( field->u.stream );
78         break;
79     default:
80         ERR("Invalid field type %d\n", field->type);
81     }
82 }
83
84 void MSI_CloseRecord( VOID *arg )
85 {
86     MSIRECORD *rec = (MSIRECORD *) arg;
87     UINT i;
88
89     for( i=0; i<rec->count; i++ )
90         MSI_FreeField( &rec->fields[i] );
91 }
92
93 MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
94 {
95     MSIHANDLE handle = 0;
96     UINT sz;
97     MSIRECORD *rec;
98
99     TRACE("%d\n", cParams);
100
101     sz = sizeof (MSIRECORD) + sizeof(MSIFIELD)*(cParams+1) ;
102     handle = alloc_msihandle( MSIHANDLETYPE_RECORD, sz, MSI_CloseRecord );
103     if( !handle )
104         return 0;
105
106     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
107     if( !rec )
108         return 0;
109
110     rec->count = cParams;
111
112     return handle;
113 }
114
115 unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
116 {
117     MSIRECORD *rec;
118
119     TRACE("%ld\n", handle );
120
121     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
122     if( !rec )
123     {
124         ERR("Record not found!\n");
125         return 0;
126     }
127
128     return rec->count;
129 }
130
131 static BOOL string2intA( LPCSTR str, int *out )
132 {
133     int x = 0;
134     LPCSTR p = str;
135
136     if( *p == '-' ) /* skip the minus sign */
137         p++;
138     while ( *p )
139     {
140         if( (*p < '0') || (*p > '9') )
141             return FALSE;
142         x *= 10;
143         x += (*p - '0');
144         p++;
145     }
146
147     if( str[0] == '-' ) /* check if it's negative */
148         x = -x;
149     *out = x; 
150
151     return TRUE;
152 }
153
154 static BOOL string2intW( LPCWSTR str, int *out )
155 {
156     int x = 0;
157     LPCWSTR p = str;
158
159     if( *p == '-' ) /* skip the minus sign */
160         p++;
161     while ( *p )
162     {
163         if( (*p < '0') || (*p > '9') )
164             return FALSE;
165         x *= 10;
166         x += (*p - '0');
167         p++;
168     }
169
170     if( str[0] == '-' ) /* check if it's negative */
171         x = -x;
172     *out = x; 
173
174     return TRUE;
175 }
176
177 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
178 {
179     MSIRECORD *rec;
180     int ret = 0;
181
182     TRACE("%ld %d\n", handle, iField );
183
184     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
185     if( !rec )
186         return MSI_NULL_INTEGER;
187
188     if( iField > rec->count )
189         return MSI_NULL_INTEGER;
190
191     switch( rec->fields[iField].type )
192     {
193     case MSIFIELD_INT:
194         return rec->fields[iField].u.iVal;
195     case MSIFIELD_STR:
196         if( string2intA( rec->fields[iField].u.szVal, &ret ) )
197             return ret;
198         return MSI_NULL_INTEGER;
199     case MSIFIELD_WSTR:
200         if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
201             return ret;
202         return MSI_NULL_INTEGER;
203     default:
204         break;
205     }
206
207     return MSI_NULL_INTEGER;
208 }
209
210 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
211 {
212     MSIRECORD *rec;
213     UINT i;
214
215     TRACE("%ld\n", handle );
216
217     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
218     if( !rec )
219         return ERROR_INVALID_HANDLE;
220
221     for( i=0; i<=rec->count; i++)
222     {
223         MSI_FreeField( &rec->fields[i] );
224         rec->fields[i].type = MSIFIELD_NULL;
225         rec->fields[i].u.iVal = 0;
226     }
227
228     return ERROR_SUCCESS;
229 }
230
231 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
232 {
233     MSIRECORD *rec;
234
235     TRACE("%ld %u %d\n", handle,iField, iVal);
236     
237     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
238     if( !rec )
239         return ERROR_INVALID_HANDLE;
240
241     if( iField > rec->count )
242         return ERROR_INVALID_FIELD;
243
244     MSI_FreeField( &rec->fields[iField] );
245     rec->fields[iField].type = MSIFIELD_INT;
246     rec->fields[iField].u.iVal = iVal;
247
248     return ERROR_SUCCESS;
249 }
250
251 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
252 {
253     MSIRECORD *rec;
254
255     TRACE("%ld %d\n", handle,iField );
256
257     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
258     if( !rec )
259         return ERROR_INVALID_HANDLE;
260
261     if( iField > rec->count ) 
262         return TRUE;
263
264     if( rec->fields[iField].type == MSIFIELD_NULL )
265         return TRUE;
266
267     return FALSE;
268 }
269
270 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField, 
271                LPSTR szValue, DWORD *pcchValue)
272 {
273     MSIRECORD *rec;
274     UINT len=0, ret;
275     CHAR buffer[16];
276
277     TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
278
279     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
280     if( !rec )
281         return ERROR_INVALID_HANDLE;
282
283     if( iField > rec->count )
284         return ERROR_INVALID_PARAMETER;
285
286     ret = ERROR_SUCCESS;
287     switch( rec->fields[iField].type )
288     {
289     case MSIFIELD_INT:
290         wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
291         len = lstrlenA( buffer );
292         lstrcpynA(szValue, buffer, *pcchValue);
293         break;
294     case MSIFIELD_STR:
295         len = lstrlenA( rec->fields[iField].u.szVal );
296         lstrcpynA(szValue, rec->fields[iField].u.szVal, *pcchValue);
297         break;
298     case MSIFIELD_WSTR:
299         len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
300                              NULL, 0 , NULL, NULL);
301         WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
302                              szValue, *pcchValue, NULL, NULL);
303         break;
304     default:
305         ret = ERROR_INVALID_PARAMETER;
306         break;
307     }
308
309     if( *pcchValue < len )
310         ret = ERROR_MORE_DATA;
311     *pcchValue = len;
312
313     return ret;
314 }
315
316 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
317                LPWSTR szValue, DWORD *pcchValue)
318 {
319     MSIRECORD *rec;
320     UINT len=0, ret;
321     WCHAR buffer[16];
322     const WCHAR szFormat[] = { '%','d',0 };
323
324     TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
325
326     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
327     if( !rec )
328         return ERROR_INVALID_HANDLE;
329
330     if( iField > rec->count )
331         return ERROR_INVALID_PARAMETER;
332
333     ret = ERROR_SUCCESS;
334     switch( rec->fields[iField].type )
335     {
336     case MSIFIELD_INT:
337         wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
338         len = lstrlenW( buffer );
339         lstrcpynW(szValue, buffer, *pcchValue);
340         break;
341     case MSIFIELD_WSTR:
342         len = lstrlenW( rec->fields[iField].u.szwVal );
343         lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
344         break;
345     case MSIFIELD_STR:
346         len = MultiByteToWideChar( CP_ACP, 0, rec->fields[iField].u.szVal, -1,
347                              NULL, 0 );
348         MultiByteToWideChar( CP_ACP, 0, rec->fields[iField].u.szVal, -1,
349                              szValue, *pcchValue);
350         break;
351     default:
352         break;
353     }
354
355     if( *pcchValue < len )
356         ret = ERROR_MORE_DATA;
357     *pcchValue = len;
358
359     return ret;
360 }
361
362 UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
363 {
364     FIXME("%ld %d\n", hRecord, iField);
365     return 0;
366 }
367
368 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
369 {
370     MSIRECORD *rec;
371     LPSTR str;
372
373     TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
374
375     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
376     if( !rec )
377         return ERROR_INVALID_HANDLE;
378
379     if( iField > rec->count )
380         return ERROR_INVALID_FIELD;
381
382     str = HeapAlloc( GetProcessHeap(), 0, (lstrlenA(szValue) + 1)*sizeof str[0]);
383     lstrcpyA( str, szValue );
384
385     MSI_FreeField( &rec->fields[iField] );
386     rec->fields[iField].type = MSIFIELD_STR;
387     rec->fields[iField].u.szVal = str;
388
389     return 0;
390 }
391
392 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
393 {
394     MSIRECORD *rec;
395     LPWSTR str;
396
397     TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
398
399     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
400     if( !rec )
401         return ERROR_INVALID_HANDLE;
402
403     if( iField > rec->count )
404         return ERROR_INVALID_FIELD;
405
406     str = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(szValue) + 1)*sizeof str[0]);
407     lstrcpyW( str, szValue );
408
409     MSI_FreeField( &rec->fields[iField] );
410     rec->fields[iField].type = MSIFIELD_WSTR;
411     rec->fields[iField].u.szwVal = str;
412
413     return 0;
414 }
415
416 UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
417 {
418     FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
419     return ERROR_CALL_NOT_IMPLEMENTED;
420 }
421
422 UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
423 {
424     FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
425     return ERROR_CALL_NOT_IMPLEMENTED;
426 }
427
428 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
429 {
430     FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
431     return ERROR_CALL_NOT_IMPLEMENTED;
432 }
433
434 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
435 {
436     FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
437     return ERROR_CALL_NOT_IMPLEMENTED;
438 }
439
440 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
441 {
442     FIXME("%ld %d %p %p\n",handle,iField,buf,sz);
443     return ERROR_CALL_NOT_IMPLEMENTED;
444 }