xref: /reactos/dll/win32/msi/record.c (revision 74f53b4b)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Implementation of the Microsoft Installer (msi.dll)
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2002-2004 Mike McCormack for CodeWeavers
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21c42b133eSAmine Khaldi #include <stdarg.h>
22c42b133eSAmine Khaldi 
23c42b133eSAmine Khaldi #define COBJMACROS
24c42b133eSAmine Khaldi 
25c42b133eSAmine Khaldi #include "windef.h"
26c42b133eSAmine Khaldi #include "winbase.h"
27c42b133eSAmine Khaldi #include "winuser.h"
28c42b133eSAmine Khaldi #include "winerror.h"
29c42b133eSAmine Khaldi #include "wine/debug.h"
30c42b133eSAmine Khaldi #include "msi.h"
31c42b133eSAmine Khaldi #include "msiquery.h"
32c2c66affSColin Finck #include "msipriv.h"
33c42b133eSAmine Khaldi #include "objidl.h"
34c42b133eSAmine Khaldi #include "winnls.h"
35c42b133eSAmine Khaldi #include "ole2.h"
36c42b133eSAmine Khaldi 
37c42b133eSAmine Khaldi #include "winreg.h"
38c42b133eSAmine Khaldi #include "shlwapi.h"
39c42b133eSAmine Khaldi 
40c42b133eSAmine Khaldi #include "query.h"
41c2c66affSColin Finck 
42c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(msidb);
43c2c66affSColin Finck 
44c2c66affSColin Finck #define MSIFIELD_NULL   0
45c2c66affSColin Finck #define MSIFIELD_INT    1
46c2c66affSColin Finck #define MSIFIELD_WSTR   3
47c2c66affSColin Finck #define MSIFIELD_STREAM 4
48c2c66affSColin Finck 
49c2c66affSColin Finck static void MSI_FreeField( MSIFIELD *field )
50c2c66affSColin Finck {
51c2c66affSColin Finck     switch( field->type )
52c2c66affSColin Finck     {
53c2c66affSColin Finck     case MSIFIELD_NULL:
54c2c66affSColin Finck     case MSIFIELD_INT:
55c2c66affSColin Finck         break;
56c2c66affSColin Finck     case MSIFIELD_WSTR:
57c2c66affSColin Finck         msi_free( field->u.szwVal);
58c2c66affSColin Finck         break;
59c2c66affSColin Finck     case MSIFIELD_STREAM:
60c2c66affSColin Finck         IStream_Release( field->u.stream );
61c2c66affSColin Finck         break;
62c2c66affSColin Finck     default:
63c2c66affSColin Finck         ERR("Invalid field type %d\n", field->type);
64c2c66affSColin Finck     }
65c2c66affSColin Finck }
66c2c66affSColin Finck 
67c2c66affSColin Finck void MSI_CloseRecord( MSIOBJECTHDR *arg )
68c2c66affSColin Finck {
69c2c66affSColin Finck     MSIRECORD *rec = (MSIRECORD *) arg;
70c2c66affSColin Finck     UINT i;
71c2c66affSColin Finck 
72c2c66affSColin Finck     for( i=0; i<=rec->count; i++ )
73c2c66affSColin Finck         MSI_FreeField( &rec->fields[i] );
74c2c66affSColin Finck }
75c2c66affSColin Finck 
76c2c66affSColin Finck MSIRECORD *MSI_CreateRecord( UINT cParams )
77c2c66affSColin Finck {
78c2c66affSColin Finck     MSIRECORD *rec;
79c2c66affSColin Finck 
80c2c66affSColin Finck     TRACE("%d\n", cParams);
81c2c66affSColin Finck 
82c2c66affSColin Finck     if( cParams>65535 )
83c2c66affSColin Finck         return NULL;
84c2c66affSColin Finck 
85c2c66affSColin Finck     rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]),
86c2c66affSColin Finck             MSI_CloseRecord );
87c2c66affSColin Finck     if( rec )
88c2c66affSColin Finck         rec->count = cParams;
89c2c66affSColin Finck     return rec;
90c2c66affSColin Finck }
91c2c66affSColin Finck 
92c2c66affSColin Finck MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
93c2c66affSColin Finck {
94c2c66affSColin Finck     MSIRECORD *rec;
95c2c66affSColin Finck     MSIHANDLE ret = 0;
96c2c66affSColin Finck 
97c2c66affSColin Finck     TRACE("%d\n", cParams);
98c2c66affSColin Finck 
99c2c66affSColin Finck     rec = MSI_CreateRecord( cParams );
100c2c66affSColin Finck     if( rec )
101c2c66affSColin Finck     {
102c2c66affSColin Finck         ret = alloc_msihandle( &rec->hdr );
103c2c66affSColin Finck         msiobj_release( &rec->hdr );
104c2c66affSColin Finck     }
105c2c66affSColin Finck     return ret;
106c2c66affSColin Finck }
107c2c66affSColin Finck 
108c2c66affSColin Finck UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
109c2c66affSColin Finck {
110c2c66affSColin Finck     return rec->count;
111c2c66affSColin Finck }
112c2c66affSColin Finck 
113c2c66affSColin Finck UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
114c2c66affSColin Finck {
115c2c66affSColin Finck     MSIRECORD *rec;
116c2c66affSColin Finck     UINT ret;
117c2c66affSColin Finck 
118c2c66affSColin Finck     TRACE("%d\n", handle );
119c2c66affSColin Finck 
120c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
121c2c66affSColin Finck     if( !rec )
122c2c66affSColin Finck         return -1;
123c2c66affSColin Finck 
124c2c66affSColin Finck     msiobj_lock( &rec->hdr );
125c2c66affSColin Finck     ret = MSI_RecordGetFieldCount( rec );
126c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
127c2c66affSColin Finck     msiobj_release( &rec->hdr );
128c2c66affSColin Finck 
129c2c66affSColin Finck     return ret;
130c2c66affSColin Finck }
131c2c66affSColin Finck 
132c2c66affSColin Finck static BOOL string2intW( LPCWSTR str, int *out )
133c2c66affSColin Finck {
134c2c66affSColin Finck     int x = 0;
135c2c66affSColin Finck     LPCWSTR p = str;
136c2c66affSColin Finck 
137c2c66affSColin Finck     if( *p == '-' ) /* skip the minus sign */
138c2c66affSColin Finck         p++;
139c2c66affSColin Finck     while ( *p )
140c2c66affSColin Finck     {
141c2c66affSColin Finck         if( (*p < '0') || (*p > '9') )
142c2c66affSColin Finck             return FALSE;
143c2c66affSColin Finck         x *= 10;
144c2c66affSColin Finck         x += (*p - '0');
145c2c66affSColin Finck         p++;
146c2c66affSColin Finck     }
147c2c66affSColin Finck 
148c2c66affSColin Finck     if( str[0] == '-' ) /* check if it's negative */
149c2c66affSColin Finck         x = -x;
150c2c66affSColin Finck     *out = x;
151c2c66affSColin Finck 
152c2c66affSColin Finck     return TRUE;
153c2c66affSColin Finck }
154c2c66affSColin Finck 
155c2c66affSColin Finck WCHAR *msi_strdupW( const WCHAR *value, int len )
156c2c66affSColin Finck {
157c2c66affSColin Finck     WCHAR *ret;
158c2c66affSColin Finck 
159c2c66affSColin Finck     if (!value) return NULL;
160c2c66affSColin Finck     if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
161c2c66affSColin Finck     memcpy( ret, value, len * sizeof(WCHAR) );
162c2c66affSColin Finck     ret[len] = 0;
163c2c66affSColin Finck     return ret;
164c2c66affSColin Finck }
165c2c66affSColin Finck 
166c2c66affSColin Finck UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
167c2c66affSColin Finck                           MSIRECORD *out_rec, UINT out_n )
168c2c66affSColin Finck {
169c2c66affSColin Finck     UINT r = ERROR_SUCCESS;
170c2c66affSColin Finck 
171c2c66affSColin Finck     msiobj_lock( &in_rec->hdr );
172c2c66affSColin Finck 
173c2c66affSColin Finck     if ( in_n > in_rec->count || out_n > out_rec->count )
174c2c66affSColin Finck         r = ERROR_FUNCTION_FAILED;
175c2c66affSColin Finck     else if ( in_rec != out_rec || in_n != out_n )
176c2c66affSColin Finck     {
177c2c66affSColin Finck         LPWSTR str;
178c2c66affSColin Finck         MSIFIELD *in, *out;
179c2c66affSColin Finck 
180c2c66affSColin Finck         in = &in_rec->fields[in_n];
181c2c66affSColin Finck         out = &out_rec->fields[out_n];
182c2c66affSColin Finck 
183c2c66affSColin Finck         switch ( in->type )
184c2c66affSColin Finck         {
185c2c66affSColin Finck         case MSIFIELD_NULL:
186c2c66affSColin Finck             break;
187c2c66affSColin Finck         case MSIFIELD_INT:
188c2c66affSColin Finck             out->u.iVal = in->u.iVal;
189c2c66affSColin Finck             break;
190c2c66affSColin Finck         case MSIFIELD_WSTR:
191c2c66affSColin Finck             if ((str = msi_strdupW( in->u.szwVal, in->len )))
192c2c66affSColin Finck             {
193c2c66affSColin Finck                 out->u.szwVal = str;
194c2c66affSColin Finck                 out->len = in->len;
195c2c66affSColin Finck             }
196c2c66affSColin Finck             else r = ERROR_OUTOFMEMORY;
197c2c66affSColin Finck             break;
198c2c66affSColin Finck         case MSIFIELD_STREAM:
199c2c66affSColin Finck             IStream_AddRef( in->u.stream );
200c2c66affSColin Finck             out->u.stream = in->u.stream;
201c2c66affSColin Finck             break;
202c2c66affSColin Finck         default:
203c2c66affSColin Finck             ERR("invalid field type %d\n", in->type);
204c2c66affSColin Finck         }
205c2c66affSColin Finck         if (r == ERROR_SUCCESS)
206c2c66affSColin Finck             out->type = in->type;
207c2c66affSColin Finck     }
208c2c66affSColin Finck 
209c2c66affSColin Finck     msiobj_unlock( &in_rec->hdr );
210c2c66affSColin Finck     return r;
211c2c66affSColin Finck }
212c2c66affSColin Finck 
213c2c66affSColin Finck int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
214c2c66affSColin Finck {
215c2c66affSColin Finck     int ret = 0;
216c2c66affSColin Finck 
217c2c66affSColin Finck     TRACE("%p %d\n", rec, iField );
218c2c66affSColin Finck 
219c2c66affSColin Finck     if( iField > rec->count )
220c2c66affSColin Finck         return MSI_NULL_INTEGER;
221c2c66affSColin Finck 
222c2c66affSColin Finck     switch( rec->fields[iField].type )
223c2c66affSColin Finck     {
224c2c66affSColin Finck     case MSIFIELD_INT:
225c2c66affSColin Finck         return rec->fields[iField].u.iVal;
226c2c66affSColin Finck     case MSIFIELD_WSTR:
227c2c66affSColin Finck         if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
228c2c66affSColin Finck             return ret;
229c2c66affSColin Finck         return MSI_NULL_INTEGER;
230c2c66affSColin Finck     default:
231c2c66affSColin Finck         break;
232c2c66affSColin Finck     }
233c2c66affSColin Finck 
234c2c66affSColin Finck     return MSI_NULL_INTEGER;
235c2c66affSColin Finck }
236c2c66affSColin Finck 
237c2c66affSColin Finck int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
238c2c66affSColin Finck {
239c2c66affSColin Finck     MSIRECORD *rec;
240c2c66affSColin Finck     UINT ret;
241c2c66affSColin Finck 
242c2c66affSColin Finck     TRACE("%d %d\n", handle, iField );
243c2c66affSColin Finck 
244c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
245c2c66affSColin Finck     if( !rec )
246c2c66affSColin Finck         return MSI_NULL_INTEGER;
247c2c66affSColin Finck 
248c2c66affSColin Finck     msiobj_lock( &rec->hdr );
249c2c66affSColin Finck     ret = MSI_RecordGetInteger( rec, iField );
250c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
251c2c66affSColin Finck     msiobj_release( &rec->hdr );
252c2c66affSColin Finck 
253c2c66affSColin Finck     return ret;
254c2c66affSColin Finck }
255c2c66affSColin Finck 
256c2c66affSColin Finck UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
257c2c66affSColin Finck {
258c2c66affSColin Finck     MSIRECORD *rec;
259c2c66affSColin Finck     UINT i;
260c2c66affSColin Finck 
261c2c66affSColin Finck     TRACE("%d\n", handle );
262c2c66affSColin Finck 
263c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
264c2c66affSColin Finck     if( !rec )
265c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
266c2c66affSColin Finck 
267c2c66affSColin Finck     msiobj_lock( &rec->hdr );
268c2c66affSColin Finck     for( i=0; i<=rec->count; i++)
269c2c66affSColin Finck     {
270c2c66affSColin Finck         MSI_FreeField( &rec->fields[i] );
271c2c66affSColin Finck         rec->fields[i].type = MSIFIELD_NULL;
272c2c66affSColin Finck         rec->fields[i].u.iVal = 0;
273c2c66affSColin Finck     }
274c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
275c2c66affSColin Finck     msiobj_release( &rec->hdr );
276c2c66affSColin Finck 
277c2c66affSColin Finck     return ERROR_SUCCESS;
278c2c66affSColin Finck }
279c2c66affSColin Finck 
280c2c66affSColin Finck UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
281c2c66affSColin Finck {
282c2c66affSColin Finck     TRACE("%p %u %d\n", rec, iField, iVal);
283c2c66affSColin Finck 
284c2c66affSColin Finck     if( iField > rec->count )
285c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
286c2c66affSColin Finck 
287c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
28871bffdcdSAmine Khaldi 
28971bffdcdSAmine Khaldi     if (iVal == MSI_NULL_INTEGER)
29071bffdcdSAmine Khaldi     {
29171bffdcdSAmine Khaldi         rec->fields[iField].type = MSIFIELD_NULL;
29271bffdcdSAmine Khaldi         rec->fields[iField].u.szwVal = NULL;
29371bffdcdSAmine Khaldi     }
29471bffdcdSAmine Khaldi     else
29571bffdcdSAmine Khaldi     {
296c2c66affSColin Finck         rec->fields[iField].type = MSIFIELD_INT;
297c2c66affSColin Finck         rec->fields[iField].u.iVal = iVal;
29871bffdcdSAmine Khaldi     }
299c2c66affSColin Finck 
300c2c66affSColin Finck     return ERROR_SUCCESS;
301c2c66affSColin Finck }
302c2c66affSColin Finck 
303c2c66affSColin Finck UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
304c2c66affSColin Finck {
305c2c66affSColin Finck     MSIRECORD *rec;
306c2c66affSColin Finck     UINT ret;
307c2c66affSColin Finck 
308c2c66affSColin Finck     TRACE("%d %u %d\n", handle, iField, iVal);
309c2c66affSColin Finck 
310c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
311c2c66affSColin Finck     if( !rec )
312c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
313c2c66affSColin Finck 
314c2c66affSColin Finck     msiobj_lock( &rec->hdr );
315c2c66affSColin Finck     ret = MSI_RecordSetInteger( rec, iField, iVal );
316c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
317c2c66affSColin Finck     msiobj_release( &rec->hdr );
318c2c66affSColin Finck     return ret;
319c2c66affSColin Finck }
320c2c66affSColin Finck 
321c2c66affSColin Finck BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
322c2c66affSColin Finck {
323c2c66affSColin Finck     BOOL r = TRUE;
324c2c66affSColin Finck 
325c2c66affSColin Finck     TRACE("%p %d\n", rec, iField );
326c2c66affSColin Finck 
327c2c66affSColin Finck     r = ( iField > rec->count ) ||
328c2c66affSColin Finck         ( rec->fields[iField].type == MSIFIELD_NULL );
329c2c66affSColin Finck 
330c2c66affSColin Finck     return r;
331c2c66affSColin Finck }
332c2c66affSColin Finck 
333c2c66affSColin Finck BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
334c2c66affSColin Finck {
335c2c66affSColin Finck     MSIRECORD *rec;
336c2c66affSColin Finck     UINT ret;
337c2c66affSColin Finck 
338c2c66affSColin Finck     TRACE("%d %d\n", handle, iField );
339c2c66affSColin Finck 
340c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
341c2c66affSColin Finck     if( !rec )
342c2c66affSColin Finck         return FALSE;
343c2c66affSColin Finck     msiobj_lock( &rec->hdr );
344c2c66affSColin Finck     ret = MSI_RecordIsNull( rec, iField );
345c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
346c2c66affSColin Finck     msiobj_release( &rec->hdr );
347c2c66affSColin Finck     return ret;
348c2c66affSColin Finck 
349c2c66affSColin Finck }
350c2c66affSColin Finck 
351c2c66affSColin Finck UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
352c2c66affSColin Finck                LPSTR szValue, LPDWORD pcchValue)
353c2c66affSColin Finck {
354c2c66affSColin Finck     UINT len = 0, ret = ERROR_SUCCESS;
355c2c66affSColin Finck     CHAR buffer[16];
356c2c66affSColin Finck 
357c2c66affSColin Finck     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
358c2c66affSColin Finck 
359c2c66affSColin Finck     if( iField > rec->count )
360c2c66affSColin Finck     {
361c2c66affSColin Finck         if ( szValue && *pcchValue > 0 )
362c2c66affSColin Finck             szValue[0] = 0;
363c2c66affSColin Finck 
364c2c66affSColin Finck         *pcchValue = 0;
365c2c66affSColin Finck         return ERROR_SUCCESS;
366c2c66affSColin Finck     }
367c2c66affSColin Finck 
368c2c66affSColin Finck     switch( rec->fields[iField].type )
369c2c66affSColin Finck     {
370c2c66affSColin Finck     case MSIFIELD_INT:
371c2c66affSColin Finck         wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
372c2c66affSColin Finck         len = lstrlenA( buffer );
373c2c66affSColin Finck         if (szValue)
374c2c66affSColin Finck             lstrcpynA(szValue, buffer, *pcchValue);
375c2c66affSColin Finck         break;
376c2c66affSColin Finck     case MSIFIELD_WSTR:
377c2c66affSColin Finck         len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
378c2c66affSColin Finck                                    rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
379c2c66affSColin Finck         if (szValue)
380c2c66affSColin Finck             WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
381c2c66affSColin Finck                                  rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
382c2c66affSColin Finck         if( szValue && *pcchValue && len>*pcchValue )
383c2c66affSColin Finck             szValue[*pcchValue-1] = 0;
384c2c66affSColin Finck         if( len )
385c2c66affSColin Finck             len--;
386c2c66affSColin Finck         break;
387c2c66affSColin Finck     case MSIFIELD_NULL:
388c2c66affSColin Finck         if( szValue && *pcchValue > 0 )
389c2c66affSColin Finck             szValue[0] = 0;
390c2c66affSColin Finck         break;
391c2c66affSColin Finck     default:
392c2c66affSColin Finck         ret = ERROR_INVALID_PARAMETER;
393c2c66affSColin Finck         break;
394c2c66affSColin Finck     }
395c2c66affSColin Finck 
396c2c66affSColin Finck     if( szValue && *pcchValue <= len )
397c2c66affSColin Finck         ret = ERROR_MORE_DATA;
398c2c66affSColin Finck     *pcchValue = len;
399c2c66affSColin Finck 
400c2c66affSColin Finck     return ret;
401c2c66affSColin Finck }
402c2c66affSColin Finck 
403c2c66affSColin Finck UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
404c2c66affSColin Finck                LPSTR szValue, LPDWORD pcchValue)
405c2c66affSColin Finck {
406c2c66affSColin Finck     MSIRECORD *rec;
407c2c66affSColin Finck     UINT ret;
408c2c66affSColin Finck 
409c2c66affSColin Finck     TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
410c2c66affSColin Finck 
411c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
412c2c66affSColin Finck     if( !rec )
413c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
414c2c66affSColin Finck     msiobj_lock( &rec->hdr );
415c2c66affSColin Finck     ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
416c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
417c2c66affSColin Finck     msiobj_release( &rec->hdr );
418c2c66affSColin Finck     return ret;
419c2c66affSColin Finck }
420c2c66affSColin Finck 
421c2c66affSColin Finck const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
422c2c66affSColin Finck {
423c2c66affSColin Finck     if (field > rec->count)
424c2c66affSColin Finck         return NULL;
425c2c66affSColin Finck 
426c2c66affSColin Finck     if (rec->fields[field].type != MSIFIELD_WSTR)
427c2c66affSColin Finck         return NULL;
428c2c66affSColin Finck 
429c2c66affSColin Finck     if (len) *len = rec->fields[field].len;
430c2c66affSColin Finck 
431c2c66affSColin Finck     return rec->fields[field].u.szwVal;
432c2c66affSColin Finck }
433c2c66affSColin Finck 
434c2c66affSColin Finck const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
435c2c66affSColin Finck {
436c2c66affSColin Finck     return msi_record_get_string( rec, iField, NULL );
437c2c66affSColin Finck }
438c2c66affSColin Finck 
439c2c66affSColin Finck UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
440c2c66affSColin Finck                LPWSTR szValue, LPDWORD pcchValue)
441c2c66affSColin Finck {
442c2c66affSColin Finck     UINT len = 0, ret = ERROR_SUCCESS;
443c2c66affSColin Finck     WCHAR buffer[16];
444c2c66affSColin Finck 
445c2c66affSColin Finck     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
446c2c66affSColin Finck 
447c2c66affSColin Finck     if( iField > rec->count )
448c2c66affSColin Finck     {
449c2c66affSColin Finck         if ( szValue && *pcchValue > 0 )
450c2c66affSColin Finck             szValue[0] = 0;
451c2c66affSColin Finck 
452c2c66affSColin Finck         *pcchValue = 0;
453c2c66affSColin Finck         return ERROR_SUCCESS;
454c2c66affSColin Finck     }
455c2c66affSColin Finck 
456c2c66affSColin Finck     switch( rec->fields[iField].type )
457c2c66affSColin Finck     {
458c2c66affSColin Finck     case MSIFIELD_INT:
459*74f53b4bSwinesync         wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal);
460c2c66affSColin Finck         len = lstrlenW( buffer );
461c2c66affSColin Finck         if (szValue)
462c2c66affSColin Finck             lstrcpynW(szValue, buffer, *pcchValue);
463c2c66affSColin Finck         break;
464c2c66affSColin Finck     case MSIFIELD_WSTR:
465c2c66affSColin Finck         len = rec->fields[iField].len;
466c2c66affSColin Finck         if (szValue)
467c2c66affSColin Finck             memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
468c2c66affSColin Finck         break;
469c2c66affSColin Finck     case MSIFIELD_NULL:
470c2c66affSColin Finck         if( szValue && *pcchValue > 0 )
471c2c66affSColin Finck             szValue[0] = 0;
472c2c66affSColin Finck         break;
473c2c66affSColin Finck     default:
474c2c66affSColin Finck         break;
475c2c66affSColin Finck     }
476c2c66affSColin Finck 
477c2c66affSColin Finck     if( szValue && *pcchValue <= len )
478c2c66affSColin Finck         ret = ERROR_MORE_DATA;
479c2c66affSColin Finck     *pcchValue = len;
480c2c66affSColin Finck 
481c2c66affSColin Finck     return ret;
482c2c66affSColin Finck }
483c2c66affSColin Finck 
484c2c66affSColin Finck UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
485c2c66affSColin Finck                LPWSTR szValue, LPDWORD pcchValue)
486c2c66affSColin Finck {
487c2c66affSColin Finck     MSIRECORD *rec;
488c2c66affSColin Finck     UINT ret;
489c2c66affSColin Finck 
490c2c66affSColin Finck     TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
491c2c66affSColin Finck 
492c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
493c2c66affSColin Finck     if( !rec )
494c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
495c2c66affSColin Finck 
496c2c66affSColin Finck     msiobj_lock( &rec->hdr );
497c2c66affSColin Finck     ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
498c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
499c2c66affSColin Finck     msiobj_release( &rec->hdr );
500c2c66affSColin Finck     return ret;
501c2c66affSColin Finck }
502c2c66affSColin Finck 
503c2c66affSColin Finck static UINT msi_get_stream_size( IStream *stm )
504c2c66affSColin Finck {
505c2c66affSColin Finck     STATSTG stat;
506c2c66affSColin Finck     HRESULT r;
507c2c66affSColin Finck 
508c2c66affSColin Finck     r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
509c2c66affSColin Finck     if( FAILED(r) )
510c2c66affSColin Finck         return 0;
511c2c66affSColin Finck     return stat.cbSize.QuadPart;
512c2c66affSColin Finck }
513c2c66affSColin Finck 
514c2c66affSColin Finck static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
515c2c66affSColin Finck {
516c2c66affSColin Finck     TRACE("%p %d\n", rec, iField);
517c2c66affSColin Finck 
518c2c66affSColin Finck     if( iField > rec->count )
519c2c66affSColin Finck         return 0;
520c2c66affSColin Finck 
521c2c66affSColin Finck     switch( rec->fields[iField].type )
522c2c66affSColin Finck     {
523c2c66affSColin Finck     case MSIFIELD_INT:
524c2c66affSColin Finck         return sizeof (INT);
525c2c66affSColin Finck     case MSIFIELD_WSTR:
526c2c66affSColin Finck         return rec->fields[iField].len;
527c2c66affSColin Finck     case MSIFIELD_NULL:
528c2c66affSColin Finck         break;
529c2c66affSColin Finck     case MSIFIELD_STREAM:
530c2c66affSColin Finck         return msi_get_stream_size( rec->fields[iField].u.stream );
531c2c66affSColin Finck     }
532c2c66affSColin Finck     return 0;
533c2c66affSColin Finck }
534c2c66affSColin Finck 
535c2c66affSColin Finck UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
536c2c66affSColin Finck {
537c2c66affSColin Finck     MSIRECORD *rec;
538c2c66affSColin Finck     UINT ret;
539c2c66affSColin Finck 
540c2c66affSColin Finck     TRACE("%d %d\n", handle, iField);
541c2c66affSColin Finck 
542c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
543c2c66affSColin Finck     if( !rec )
544c2c66affSColin Finck         return 0;
545c2c66affSColin Finck     msiobj_lock( &rec->hdr );
546c2c66affSColin Finck     ret = MSI_RecordDataSize( rec, iField);
547c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
548c2c66affSColin Finck     msiobj_release( &rec->hdr );
549c2c66affSColin Finck     return ret;
550c2c66affSColin Finck }
551c2c66affSColin Finck 
552c2c66affSColin Finck UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
553c2c66affSColin Finck {
554c2c66affSColin Finck     WCHAR *valueW = NULL;
555c2c66affSColin Finck     MSIRECORD *rec;
556c2c66affSColin Finck     UINT ret;
557c2c66affSColin Finck 
558c2c66affSColin Finck     TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
559c2c66affSColin Finck 
560c2c66affSColin Finck     if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
561c2c66affSColin Finck 
562c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
563c2c66affSColin Finck     if( !rec )
564c2c66affSColin Finck     {
565c2c66affSColin Finck         msi_free( valueW );
566c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
567c2c66affSColin Finck     }
568c2c66affSColin Finck     msiobj_lock( &rec->hdr );
569c2c66affSColin Finck     ret = MSI_RecordSetStringW( rec, iField, valueW );
570c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
571c2c66affSColin Finck     msiobj_release( &rec->hdr );
572c2c66affSColin Finck     msi_free( valueW );
573c2c66affSColin Finck     return ret;
574c2c66affSColin Finck }
575c2c66affSColin Finck 
576c2c66affSColin Finck UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
577c2c66affSColin Finck {
578c2c66affSColin Finck     if (field > rec->count)
579c2c66affSColin Finck         return ERROR_INVALID_FIELD;
580c2c66affSColin Finck 
581c2c66affSColin Finck     MSI_FreeField( &rec->fields[field] );
582c2c66affSColin Finck 
583958f1addSwinesync     if (value && len < 0) len = lstrlenW( value );
584c2c66affSColin Finck 
585c2c66affSColin Finck     if (value && len)
586c2c66affSColin Finck     {
587c2c66affSColin Finck         rec->fields[field].type = MSIFIELD_WSTR;
588c2c66affSColin Finck         rec->fields[field].u.szwVal = msi_strdupW( value, len );
589c2c66affSColin Finck         rec->fields[field].len = len;
590c2c66affSColin Finck     }
591c2c66affSColin Finck     else
592c2c66affSColin Finck     {
593c2c66affSColin Finck         rec->fields[field].type = MSIFIELD_NULL;
594c2c66affSColin Finck         rec->fields[field].u.szwVal = NULL;
595c2c66affSColin Finck         rec->fields[field].len = 0;
596c2c66affSColin Finck     }
597c2c66affSColin Finck     return 0;
598c2c66affSColin Finck }
599c2c66affSColin Finck 
600c2c66affSColin Finck UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
601c2c66affSColin Finck {
602c2c66affSColin Finck     TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
603c2c66affSColin Finck 
604c2c66affSColin Finck     return msi_record_set_string( rec, iField, szValue, -1 );
605c2c66affSColin Finck }
606c2c66affSColin Finck 
607c2c66affSColin Finck UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
608c2c66affSColin Finck {
609c2c66affSColin Finck     MSIRECORD *rec;
610c2c66affSColin Finck     UINT ret;
611c2c66affSColin Finck 
612c2c66affSColin Finck     TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
613c2c66affSColin Finck 
614c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
615c2c66affSColin Finck     if( !rec )
616c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
617c2c66affSColin Finck 
618c2c66affSColin Finck     msiobj_lock( &rec->hdr );
619c2c66affSColin Finck     ret = MSI_RecordSetStringW( rec, iField, szValue );
620c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
621c2c66affSColin Finck     msiobj_release( &rec->hdr );
622c2c66affSColin Finck     return ret;
623c2c66affSColin Finck }
624c2c66affSColin Finck 
625c2c66affSColin Finck /* read the data in a file into an IStream */
626c2c66affSColin Finck static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
627c2c66affSColin Finck {
628c2c66affSColin Finck     DWORD sz, szHighWord = 0, read;
629c2c66affSColin Finck     HANDLE handle;
630c2c66affSColin Finck     HGLOBAL hGlob = 0;
631c2c66affSColin Finck     HRESULT hr;
632c2c66affSColin Finck     ULARGE_INTEGER ulSize;
633c2c66affSColin Finck 
634c2c66affSColin Finck     TRACE("reading %s\n", debugstr_w(szFile));
635c2c66affSColin Finck 
636c2c66affSColin Finck     /* read the file into memory */
637c2c66affSColin Finck     handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
638c2c66affSColin Finck     if( handle == INVALID_HANDLE_VALUE )
639c2c66affSColin Finck         return GetLastError();
640c2c66affSColin Finck     sz = GetFileSize(handle, &szHighWord);
641c2c66affSColin Finck     if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
642c2c66affSColin Finck     {
643c2c66affSColin Finck         hGlob = GlobalAlloc(GMEM_FIXED, sz);
644c2c66affSColin Finck         if( hGlob )
645c2c66affSColin Finck         {
646c2c66affSColin Finck             BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
647c2c66affSColin Finck             if( !r )
648c2c66affSColin Finck             {
649c2c66affSColin Finck                 GlobalFree(hGlob);
650c2c66affSColin Finck                 hGlob = 0;
651c2c66affSColin Finck             }
652c2c66affSColin Finck         }
653c2c66affSColin Finck     }
654c2c66affSColin Finck     CloseHandle(handle);
655c2c66affSColin Finck     if( !hGlob )
656c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
657c2c66affSColin Finck 
658c2c66affSColin Finck     /* make a stream out of it, and set the correct file size */
659c2c66affSColin Finck     hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
660c2c66affSColin Finck     if( FAILED( hr ) )
661c2c66affSColin Finck     {
662c2c66affSColin Finck         GlobalFree(hGlob);
663c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
664c2c66affSColin Finck     }
665c2c66affSColin Finck 
666c2c66affSColin Finck     /* set the correct size - CreateStreamOnHGlobal screws it up */
667c2c66affSColin Finck     ulSize.QuadPart = sz;
668c2c66affSColin Finck     IStream_SetSize(*pstm, ulSize);
669c2c66affSColin Finck 
670c2c66affSColin Finck     TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
671c2c66affSColin Finck 
672c2c66affSColin Finck     return ERROR_SUCCESS;
673c2c66affSColin Finck }
674c2c66affSColin Finck 
675c2c66affSColin Finck UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
676c2c66affSColin Finck {
677c2c66affSColin Finck     if ( (iField == 0) || (iField > rec->count) )
678c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
679c2c66affSColin Finck 
680c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
681c2c66affSColin Finck     rec->fields[iField].type = MSIFIELD_STREAM;
682c2c66affSColin Finck     rec->fields[iField].u.stream = stream;
683c2c66affSColin Finck 
684c2c66affSColin Finck     return ERROR_SUCCESS;
685c2c66affSColin Finck }
686c2c66affSColin Finck 
687c2c66affSColin Finck UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
688c2c66affSColin Finck {
689c2c66affSColin Finck     IStream *stm = NULL;
690c2c66affSColin Finck     HRESULT hr;
691c2c66affSColin Finck     UINT ret;
692c2c66affSColin Finck 
693c2c66affSColin Finck     if( (iField == 0) || (iField > rec->count) )
694c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
695c2c66affSColin Finck 
696c2c66affSColin Finck     /* no filename means we should seek back to the start of the stream */
697c2c66affSColin Finck     if( !szFilename )
698c2c66affSColin Finck     {
699c2c66affSColin Finck         LARGE_INTEGER ofs;
700c2c66affSColin Finck         ULARGE_INTEGER cur;
701c2c66affSColin Finck 
702c2c66affSColin Finck         if( rec->fields[iField].type != MSIFIELD_STREAM )
703c2c66affSColin Finck             return ERROR_INVALID_FIELD;
704c2c66affSColin Finck 
705c2c66affSColin Finck         stm = rec->fields[iField].u.stream;
706c2c66affSColin Finck         if( !stm )
707c2c66affSColin Finck             return ERROR_INVALID_FIELD;
708c2c66affSColin Finck 
709c2c66affSColin Finck         ofs.QuadPart = 0;
710c2c66affSColin Finck         hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
711c2c66affSColin Finck         if (FAILED( hr ))
712c2c66affSColin Finck             return ERROR_FUNCTION_FAILED;
713c2c66affSColin Finck     }
714c2c66affSColin Finck     else
715c2c66affSColin Finck     {
716c2c66affSColin Finck         /* read the file into a stream and save the stream in the record */
717c2c66affSColin Finck         ret = RECORD_StreamFromFile(szFilename, &stm);
718c2c66affSColin Finck         if (ret != ERROR_SUCCESS)
719c2c66affSColin Finck             return ret;
720c2c66affSColin Finck 
721c2c66affSColin Finck         /* if all's good, store it in the record */
722c2c66affSColin Finck         MSI_RecordSetStream(rec, iField, stm);
723c2c66affSColin Finck     }
724c2c66affSColin Finck 
725c2c66affSColin Finck     return ERROR_SUCCESS;
726c2c66affSColin Finck }
727c2c66affSColin Finck 
728c2c66affSColin Finck UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
729c2c66affSColin Finck {
730c2c66affSColin Finck     LPWSTR wstr = NULL;
731c2c66affSColin Finck     UINT ret;
732c2c66affSColin Finck 
733c2c66affSColin Finck     TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
734c2c66affSColin Finck 
735c2c66affSColin Finck     if( szFilename )
736c2c66affSColin Finck     {
737c2c66affSColin Finck         wstr = strdupAtoW( szFilename );
738c2c66affSColin Finck         if( !wstr )
739c2c66affSColin Finck              return ERROR_OUTOFMEMORY;
740c2c66affSColin Finck     }
741c2c66affSColin Finck     ret = MsiRecordSetStreamW(hRecord, iField, wstr);
742c2c66affSColin Finck     msi_free(wstr);
743c2c66affSColin Finck 
744c2c66affSColin Finck     return ret;
745c2c66affSColin Finck }
746c2c66affSColin Finck 
747c2c66affSColin Finck UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
748c2c66affSColin Finck {
749c2c66affSColin Finck     MSIRECORD *rec;
750c2c66affSColin Finck     UINT ret;
751c2c66affSColin Finck 
752c2c66affSColin Finck     TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
753c2c66affSColin Finck 
754c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
755c2c66affSColin Finck     if( !rec )
756c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
757c2c66affSColin Finck 
758c2c66affSColin Finck     msiobj_lock( &rec->hdr );
759c2c66affSColin Finck     ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
760c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
761c2c66affSColin Finck     msiobj_release( &rec->hdr );
762c2c66affSColin Finck     return ret;
763c2c66affSColin Finck }
764c2c66affSColin Finck 
765c2c66affSColin Finck UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
766c2c66affSColin Finck {
767c2c66affSColin Finck     ULONG count;
768c2c66affSColin Finck     HRESULT r;
769c2c66affSColin Finck     IStream *stm;
770c2c66affSColin Finck 
771c2c66affSColin Finck     TRACE("%p %d %p %p\n", rec, iField, buf, sz);
772c2c66affSColin Finck 
773c2c66affSColin Finck     if( !sz )
774c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
775c2c66affSColin Finck 
776c2c66affSColin Finck     if( iField > rec->count)
777c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
778c2c66affSColin Finck 
779c2c66affSColin Finck     if ( rec->fields[iField].type == MSIFIELD_NULL )
780c2c66affSColin Finck     {
781c2c66affSColin Finck         *sz = 0;
782c2c66affSColin Finck         return ERROR_INVALID_DATA;
783c2c66affSColin Finck     }
784c2c66affSColin Finck 
785c2c66affSColin Finck     if( rec->fields[iField].type != MSIFIELD_STREAM )
786c2c66affSColin Finck         return ERROR_INVALID_DATATYPE;
787c2c66affSColin Finck 
788c2c66affSColin Finck     stm = rec->fields[iField].u.stream;
789c2c66affSColin Finck     if( !stm )
790c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
791c2c66affSColin Finck 
792c2c66affSColin Finck     /* if there's no buffer pointer, calculate the length to the end */
793c2c66affSColin Finck     if( !buf )
794c2c66affSColin Finck     {
795c2c66affSColin Finck         LARGE_INTEGER ofs;
796c2c66affSColin Finck         ULARGE_INTEGER end, cur;
797c2c66affSColin Finck 
798c2c66affSColin Finck         ofs.QuadPart = cur.QuadPart = 0;
799c2c66affSColin Finck         end.QuadPart = 0;
800c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
801c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
802c2c66affSColin Finck         ofs.QuadPart = cur.QuadPart;
803c2c66affSColin Finck         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
804c2c66affSColin Finck         *sz = end.QuadPart - cur.QuadPart;
805c2c66affSColin Finck 
806c2c66affSColin Finck         return ERROR_SUCCESS;
807c2c66affSColin Finck     }
808c2c66affSColin Finck 
809c2c66affSColin Finck     /* read the data */
810c2c66affSColin Finck     count = 0;
811c2c66affSColin Finck     r = IStream_Read( stm, buf, *sz, &count );
812c2c66affSColin Finck     if( FAILED( r ) )
813c2c66affSColin Finck     {
814c2c66affSColin Finck         *sz = 0;
815c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
816c2c66affSColin Finck     }
817c2c66affSColin Finck 
818c2c66affSColin Finck     *sz = count;
819c2c66affSColin Finck 
820c2c66affSColin Finck     return ERROR_SUCCESS;
821c2c66affSColin Finck }
822c2c66affSColin Finck 
823c2c66affSColin Finck UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
824c2c66affSColin Finck {
825c2c66affSColin Finck     MSIRECORD *rec;
826c2c66affSColin Finck     UINT ret;
827c2c66affSColin Finck 
828c2c66affSColin Finck     TRACE("%d %d %p %p\n", handle, iField, buf, sz);
829c2c66affSColin Finck 
830c2c66affSColin Finck     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
831c2c66affSColin Finck     if( !rec )
832c2c66affSColin Finck         return ERROR_INVALID_HANDLE;
833c2c66affSColin Finck     msiobj_lock( &rec->hdr );
834c2c66affSColin Finck     ret = MSI_RecordReadStream( rec, iField, buf, sz );
835c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
836c2c66affSColin Finck     msiobj_release( &rec->hdr );
837c2c66affSColin Finck     return ret;
838c2c66affSColin Finck }
839c2c66affSColin Finck 
840c2c66affSColin Finck UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
841c2c66affSColin Finck {
842c2c66affSColin Finck     TRACE("%p %d %p\n", rec, iField, stm);
843c2c66affSColin Finck 
844c2c66affSColin Finck     if( iField > rec->count )
845c2c66affSColin Finck         return ERROR_INVALID_FIELD;
846c2c66affSColin Finck 
847c2c66affSColin Finck     MSI_FreeField( &rec->fields[iField] );
848c2c66affSColin Finck 
849c2c66affSColin Finck     rec->fields[iField].type = MSIFIELD_STREAM;
850c2c66affSColin Finck     rec->fields[iField].u.stream = stm;
851c2c66affSColin Finck     IStream_AddRef( stm );
852c2c66affSColin Finck 
853c2c66affSColin Finck     return ERROR_SUCCESS;
854c2c66affSColin Finck }
855c2c66affSColin Finck 
856c2c66affSColin Finck UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
857c2c66affSColin Finck {
858c2c66affSColin Finck     TRACE("%p %d %p\n", rec, iField, pstm);
859c2c66affSColin Finck 
860c2c66affSColin Finck     if( iField > rec->count )
861c2c66affSColin Finck         return ERROR_INVALID_FIELD;
862c2c66affSColin Finck 
863c2c66affSColin Finck     if( rec->fields[iField].type != MSIFIELD_STREAM )
864c2c66affSColin Finck         return ERROR_INVALID_FIELD;
865c2c66affSColin Finck 
866c2c66affSColin Finck     *pstm = rec->fields[iField].u.stream;
867c2c66affSColin Finck     IStream_AddRef( *pstm );
868c2c66affSColin Finck 
869c2c66affSColin Finck     return ERROR_SUCCESS;
870c2c66affSColin Finck }
871c2c66affSColin Finck 
872c2c66affSColin Finck static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
873c2c66affSColin Finck {
874c2c66affSColin Finck     ULARGE_INTEGER size;
875c2c66affSColin Finck     LARGE_INTEGER pos;
876c2c66affSColin Finck     IStream *out;
877c2c66affSColin Finck     DWORD stgm;
878c2c66affSColin Finck     HRESULT r;
879c2c66affSColin Finck 
880c2c66affSColin Finck     stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
881c2c66affSColin Finck     r = SHCreateStreamOnFileW( name, stgm, &out );
882c2c66affSColin Finck     if( FAILED( r ) )
883c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
884c2c66affSColin Finck 
885c2c66affSColin Finck     pos.QuadPart = 0;
886c2c66affSColin Finck     r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
887c2c66affSColin Finck     if( FAILED( r ) )
888c2c66affSColin Finck         goto end;
889c2c66affSColin Finck 
890c2c66affSColin Finck     pos.QuadPart = 0;
891c2c66affSColin Finck     r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
892c2c66affSColin Finck     if( FAILED( r ) )
893c2c66affSColin Finck         goto end;
894c2c66affSColin Finck 
895c2c66affSColin Finck     r = IStream_CopyTo( stm, out, size, NULL, NULL );
896c2c66affSColin Finck 
897c2c66affSColin Finck end:
898c2c66affSColin Finck     IStream_Release( out );
899c2c66affSColin Finck     if( FAILED( r ) )
900c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
901c2c66affSColin Finck     return ERROR_SUCCESS;
902c2c66affSColin Finck }
903c2c66affSColin Finck 
904c2c66affSColin Finck UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
905c2c66affSColin Finck {
906c2c66affSColin Finck     IStream *stm = NULL;
907c2c66affSColin Finck     UINT r;
908c2c66affSColin Finck 
909c2c66affSColin Finck     TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
910c2c66affSColin Finck 
911c2c66affSColin Finck     msiobj_lock( &rec->hdr );
912c2c66affSColin Finck 
913c2c66affSColin Finck     r = MSI_RecordGetIStream( rec, iField, &stm );
914c2c66affSColin Finck     if( r == ERROR_SUCCESS )
915c2c66affSColin Finck     {
916c2c66affSColin Finck         r = msi_dump_stream_to_file( stm, name );
917c2c66affSColin Finck         IStream_Release( stm );
918c2c66affSColin Finck     }
919c2c66affSColin Finck 
920c2c66affSColin Finck     msiobj_unlock( &rec->hdr );
921c2c66affSColin Finck 
922c2c66affSColin Finck     return r;
923c2c66affSColin Finck }
924c2c66affSColin Finck 
925c2c66affSColin Finck MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
926c2c66affSColin Finck {
927c2c66affSColin Finck     MSIRECORD *clone;
928c2c66affSColin Finck     UINT r, i, count;
929c2c66affSColin Finck 
930c2c66affSColin Finck     count = MSI_RecordGetFieldCount(rec);
931c2c66affSColin Finck     clone = MSI_CreateRecord(count);
932c2c66affSColin Finck     if (!clone)
933c2c66affSColin Finck         return NULL;
934c2c66affSColin Finck 
935c2c66affSColin Finck     for (i = 0; i <= count; i++)
936c2c66affSColin Finck     {
937c2c66affSColin Finck         if (rec->fields[i].type == MSIFIELD_STREAM)
938c2c66affSColin Finck         {
939c2c66affSColin Finck             if (FAILED(IStream_Clone(rec->fields[i].u.stream,
940c2c66affSColin Finck                                      &clone->fields[i].u.stream)))
941c2c66affSColin Finck             {
942c2c66affSColin Finck                 msiobj_release(&clone->hdr);
943c2c66affSColin Finck                 return NULL;
944c2c66affSColin Finck             }
945c2c66affSColin Finck             clone->fields[i].type = MSIFIELD_STREAM;
946c2c66affSColin Finck         }
947c2c66affSColin Finck         else
948c2c66affSColin Finck         {
949c2c66affSColin Finck             r = MSI_RecordCopyField(rec, i, clone, i);
950c2c66affSColin Finck             if (r != ERROR_SUCCESS)
951c2c66affSColin Finck             {
952c2c66affSColin Finck                 msiobj_release(&clone->hdr);
953c2c66affSColin Finck                 return NULL;
954c2c66affSColin Finck             }
955c2c66affSColin Finck         }
956c2c66affSColin Finck     }
957c2c66affSColin Finck 
958c2c66affSColin Finck     return clone;
959c2c66affSColin Finck }
960c2c66affSColin Finck 
961c2c66affSColin Finck BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
962c2c66affSColin Finck {
963c2c66affSColin Finck     if (a->fields[field].type != b->fields[field].type)
964c2c66affSColin Finck         return FALSE;
965c2c66affSColin Finck 
966c2c66affSColin Finck     switch (a->fields[field].type)
967c2c66affSColin Finck     {
968c2c66affSColin Finck         case MSIFIELD_NULL:
969c2c66affSColin Finck             break;
970c2c66affSColin Finck 
971c2c66affSColin Finck         case MSIFIELD_INT:
972c2c66affSColin Finck             if (a->fields[field].u.iVal != b->fields[field].u.iVal)
973c2c66affSColin Finck                 return FALSE;
974c2c66affSColin Finck             break;
975c2c66affSColin Finck 
976c2c66affSColin Finck         case MSIFIELD_WSTR:
977c2c66affSColin Finck             if (a->fields[field].len != b->fields[field].len) return FALSE;
978c2c66affSColin Finck             if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
979c2c66affSColin Finck                         a->fields[field].len * sizeof(WCHAR) )) return FALSE;
980c2c66affSColin Finck             break;
981c2c66affSColin Finck 
982c2c66affSColin Finck         case MSIFIELD_STREAM:
983c2c66affSColin Finck         default:
984c2c66affSColin Finck             return FALSE;
985c2c66affSColin Finck     }
986c2c66affSColin Finck     return TRUE;
987c2c66affSColin Finck }
988c2c66affSColin Finck 
989c2c66affSColin Finck 
990c2c66affSColin Finck BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
991c2c66affSColin Finck {
992c2c66affSColin Finck     UINT i;
993c2c66affSColin Finck 
994c2c66affSColin Finck     if (a->count != b->count)
995c2c66affSColin Finck         return FALSE;
996c2c66affSColin Finck 
997c2c66affSColin Finck     for (i = 0; i <= a->count; i++)
998c2c66affSColin Finck     {
999c2c66affSColin Finck         if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1000c2c66affSColin Finck             return FALSE;
1001c2c66affSColin Finck     }
1002c2c66affSColin Finck 
1003c2c66affSColin Finck     return TRUE;
1004c2c66affSColin Finck }
1005c2c66affSColin Finck 
1006c2c66affSColin Finck WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1007c2c66affSColin Finck {
1008c2c66affSColin Finck     DWORD sz = 0;
1009c2c66affSColin Finck     WCHAR *str;
1010c2c66affSColin Finck     UINT r;
1011c2c66affSColin Finck 
1012c2c66affSColin Finck     if (MSI_RecordIsNull( rec, field )) return NULL;
1013c2c66affSColin Finck 
1014c2c66affSColin Finck     r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1015c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1016c2c66affSColin Finck         return NULL;
1017c2c66affSColin Finck 
1018c2c66affSColin Finck     sz++;
1019c2c66affSColin Finck     str = msi_alloc( sz * sizeof(WCHAR) );
1020c2c66affSColin Finck     if (!str) return NULL;
1021c2c66affSColin Finck     str[0] = 0;
1022c2c66affSColin Finck     r = MSI_RecordGetStringW( rec, field, str, &sz );
1023c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1024c2c66affSColin Finck     {
1025c2c66affSColin Finck         ERR("failed to get string!\n");
1026c2c66affSColin Finck         msi_free( str );
1027c2c66affSColin Finck         return NULL;
1028c2c66affSColin Finck     }
1029c2c66affSColin Finck     return str;
1030c2c66affSColin Finck }
103171bffdcdSAmine Khaldi 
103271bffdcdSAmine Khaldi void dump_record(MSIRECORD *rec)
103371bffdcdSAmine Khaldi {
103471bffdcdSAmine Khaldi     int i;
103571bffdcdSAmine Khaldi     if (!rec)
103671bffdcdSAmine Khaldi     {
103771bffdcdSAmine Khaldi         TRACE("(null)\n");
103871bffdcdSAmine Khaldi         return;
103971bffdcdSAmine Khaldi     }
104071bffdcdSAmine Khaldi 
104171bffdcdSAmine Khaldi     TRACE("[");
104271bffdcdSAmine Khaldi     for (i = 0; i <= rec->count; i++)
104371bffdcdSAmine Khaldi     {
104471bffdcdSAmine Khaldi         switch(rec->fields[i].type)
104571bffdcdSAmine Khaldi         {
104671bffdcdSAmine Khaldi         case MSIFIELD_NULL: TRACE("(null)"); break;
104771bffdcdSAmine Khaldi         case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
104871bffdcdSAmine Khaldi         case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
104971bffdcdSAmine Khaldi         case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
105071bffdcdSAmine Khaldi         }
105171bffdcdSAmine Khaldi         if (i < rec->count) TRACE(", ");
105271bffdcdSAmine Khaldi     }
105371bffdcdSAmine Khaldi     TRACE("]\n");
105471bffdcdSAmine Khaldi }
10552e19edd6Swinesync 
1056aede536cSwinesync UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
10572e19edd6Swinesync {
10582e19edd6Swinesync     MSIRECORD *rec;
10592e19edd6Swinesync     unsigned int i;
10608c04add1Swinesync     UINT r = ERROR_SUCCESS;
10612e19edd6Swinesync 
1062aede536cSwinesync     if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1063aede536cSwinesync         return ERROR_INVALID_HANDLE;
10642e19edd6Swinesync 
106514478462Swinesync     rec->cookie = in->cookie;
10662e19edd6Swinesync     for (i = 0; i <= in->count; i++)
10672e19edd6Swinesync     {
10682e19edd6Swinesync         switch (in->fields[i].type)
10692e19edd6Swinesync         {
10702e19edd6Swinesync         case MSIFIELD_NULL:
1071aede536cSwinesync             MSI_FreeField(&rec->fields[i]);
1072aede536cSwinesync             rec->fields[i].type = MSIFIELD_NULL;
10732e19edd6Swinesync             break;
10742e19edd6Swinesync         case MSIFIELD_INT:
10752e19edd6Swinesync             r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
10762e19edd6Swinesync             break;
10772e19edd6Swinesync         case MSIFIELD_WSTR:
10782e19edd6Swinesync             r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
10792e19edd6Swinesync             break;
10802e19edd6Swinesync         case MSIFIELD_STREAM:
10812e19edd6Swinesync             r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
10822e19edd6Swinesync             break;
10832e19edd6Swinesync         default:
10842e19edd6Swinesync             ERR("invalid field type %d\n", in->fields[i].type);
10852e19edd6Swinesync             break;
10862e19edd6Swinesync         }
10872e19edd6Swinesync 
10882e19edd6Swinesync         if (r)
10892e19edd6Swinesync         {
10902e19edd6Swinesync             msiobj_release(&rec->hdr);
10912e19edd6Swinesync             return r;
10922e19edd6Swinesync         }
10932e19edd6Swinesync     }
10942e19edd6Swinesync 
10952e19edd6Swinesync     msiobj_release(&rec->hdr);
10962e19edd6Swinesync     return ERROR_SUCCESS;
10972e19edd6Swinesync }
1098795da528Swinesync 
1099aede536cSwinesync UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1100aede536cSwinesync {
1101aede536cSwinesync     if (!in)
1102aede536cSwinesync     {
1103aede536cSwinesync         *out = 0;
1104aede536cSwinesync         return ERROR_SUCCESS;
1105aede536cSwinesync     }
1106aede536cSwinesync 
1107aede536cSwinesync     *out = MsiCreateRecord(in->count);
1108aede536cSwinesync     if (!*out) return ERROR_OUTOFMEMORY;
1109aede536cSwinesync 
1110aede536cSwinesync     return copy_remote_record(in, *out);
1111aede536cSwinesync }
1112aede536cSwinesync 
1113795da528Swinesync struct wire_record *marshal_record(MSIHANDLE handle)
1114795da528Swinesync {
1115795da528Swinesync     struct wire_record *ret;
111614478462Swinesync     unsigned int i;
1117795da528Swinesync     MSIRECORD *rec;
1118795da528Swinesync 
1119795da528Swinesync     if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1120795da528Swinesync         return NULL;
1121795da528Swinesync 
112214478462Swinesync     ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
112314478462Swinesync     ret->count = rec->count;
112414478462Swinesync     ret->cookie = rec->cookie;
1125795da528Swinesync 
112614478462Swinesync     for (i = 0; i <= rec->count; i++)
1127795da528Swinesync     {
1128795da528Swinesync         switch (rec->fields[i].type)
1129795da528Swinesync         {
1130795da528Swinesync         case MSIFIELD_NULL:
1131795da528Swinesync             break;
1132795da528Swinesync         case MSIFIELD_INT:
1133795da528Swinesync             ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1134795da528Swinesync             break;
1135795da528Swinesync         case MSIFIELD_WSTR:
1136795da528Swinesync             ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal);
1137795da528Swinesync             break;
1138795da528Swinesync         case MSIFIELD_STREAM:
1139795da528Swinesync             IStream_AddRef(rec->fields[i].u.stream);
1140795da528Swinesync             ret->fields[i].u.stream = rec->fields[i].u.stream;
1141795da528Swinesync             break;
1142795da528Swinesync         default:
1143795da528Swinesync             ERR("invalid field type %d\n", rec->fields[i].type);
1144795da528Swinesync             break;
1145795da528Swinesync         }
1146795da528Swinesync         ret->fields[i].type = rec->fields[i].type;
1147795da528Swinesync     }
1148795da528Swinesync 
1149795da528Swinesync     msiobj_release(&rec->hdr);
1150795da528Swinesync     return ret;
1151795da528Swinesync }
1152795da528Swinesync 
1153795da528Swinesync void free_remote_record(struct wire_record *rec)
1154795da528Swinesync {
1155795da528Swinesync     int i;
1156795da528Swinesync 
1157795da528Swinesync     for (i = 0; i <= rec->count; i++)
1158795da528Swinesync     {
1159795da528Swinesync         if (rec->fields[i].type == MSIFIELD_WSTR)
1160795da528Swinesync             midl_user_free(rec->fields[i].u.szwVal);
1161795da528Swinesync         else if (rec->fields[i].type == MSIFIELD_STREAM)
1162795da528Swinesync             IStream_Release(rec->fields[i].u.stream);
1163795da528Swinesync     }
1164795da528Swinesync 
1165795da528Swinesync     midl_user_free(rec);
1166795da528Swinesync }
1167