ReactOS  0.4.15-dev-5122-g72bdbdd
database.c
Go to the documentation of this file.
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #define COBJMACROS
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "objidl.h"
35 #include "objbase.h"
36 #include "msiserver.h"
37 #include "query.h"
38 
39 #include "initguid.h"
40 
42 
43 /*
44  * .MSI file format
45  *
46  * An .msi file is a structured storage file.
47  * It contains a number of streams.
48  * A stream for each table in the database.
49  * Two streams for the string table in the database.
50  * Any binary data in a table is a reference to a stream.
51  */
52 
53 #define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0)
54 
55 static void free_transforms( MSIDATABASE *db )
56 {
57  while( !list_empty( &db->transforms ) )
58  {
60  list_remove( &t->entry );
61  IStorage_Release( t->stg );
62  msi_free( t );
63  }
64 }
65 
66 static void free_streams( MSIDATABASE *db )
67 {
68  UINT i;
69  for (i = 0; i < db->num_streams; i++)
70  {
71  if (db->streams[i].stream) IStream_Release( db->streams[i].stream );
72  }
73  msi_free( db->streams );
74 }
75 
77 {
78  MSITRANSFORM *t;
79 
80  t = msi_alloc( sizeof *t );
81  t->stg = stg;
82  IStorage_AddRef( stg );
83  list_add_head( &db->transforms, &t->entry );
84 }
85 
87 {
88  MSIDATABASE *db = (MSIDATABASE *) arg;
89 
90  msi_free(db->path);
91  free_streams( db );
92  free_cached_tables( db );
93  free_transforms( db );
94  if (db->strings) msi_destroy_stringtable( db->strings );
95  IStorage_Release( db->storage );
96  if (db->deletefile)
97  {
98  DeleteFileW( db->deletefile );
99  msi_free( db->deletefile );
100  }
101  msi_free( db->tempfolder );
102 }
103 
104 static HRESULT db_initialize( IStorage *stg, const GUID *clsid )
105 {
106  HRESULT hr;
107 
108  hr = IStorage_SetClass( stg, clsid );
109  if (FAILED( hr ))
110  {
111  WARN("failed to set class id %#lx\n", hr);
112  return hr;
113  }
114 
115  /* create the _Tables stream */
116  hr = write_stream_data( stg, L"_Tables", NULL, 0, TRUE );
117  if (FAILED( hr ))
118  {
119  WARN("failed to create _Tables stream %#lx\n", hr);
120  return hr;
121  }
122 
123  hr = msi_init_string_table( stg );
124  if (FAILED( hr ))
125  {
126  WARN("failed to initialize string table %#lx\n", hr);
127  return hr;
128  }
129 
130  hr = IStorage_Commit( stg, 0 );
131  if (FAILED( hr ))
132  {
133  WARN("failed to commit changes %#lx\n", hr);
134  return hr;
135  }
136 
137  return S_OK;
138 }
139 
141 {
142  IStorage *stg = NULL;
143  HRESULT r;
144  MSIDATABASE *db = NULL;
147  UINT mode;
148  STATSTG stat;
149  BOOL created = FALSE, patch = FALSE;
151 
152  TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
153 
154  if( !pdb )
156 
157  save_path = szDBPath;
158  if ( IS_INTMSIDBOPEN(szPersist) )
159  {
160  mode = LOWORD(szPersist);
161  }
162  else
163  {
164  if (!CopyFileW( szDBPath, szPersist, FALSE ))
165  return ERROR_OPEN_FAILED;
166 
167  szDBPath = szPersist;
169  created = TRUE;
170  }
171 
173  {
174  TRACE("Database is a patch\n");
176  patch = TRUE;
177  }
178 
179  if( mode == MSI_OPEN_READONLY )
180  {
181  r = StgOpenStorage( szDBPath, NULL,
183  }
184  else if( mode == MSI_OPEN_CREATE )
185  {
186  r = StgCreateDocfile( szDBPath,
188 
189  if( SUCCEEDED(r) )
190  r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
191  created = TRUE;
192  }
193  else if( mode == MSI_OPEN_CREATEDIRECT )
194  {
195  r = StgCreateDocfile( szDBPath,
197 
198  if( SUCCEEDED(r) )
199  r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
200  created = TRUE;
201  }
202  else if( mode == MSI_OPEN_TRANSACT )
203  {
204  r = StgOpenStorage( szDBPath, NULL,
206  }
207  else if( mode == MSI_OPEN_DIRECT )
208  {
209  r = StgOpenStorage( szDBPath, NULL,
211  }
212  else
213  {
214  ERR("unknown flag %x\n",mode);
216  }
217 
218  if( FAILED( r ) || !stg )
219  {
220  WARN("open failed r = %#lx for %s\n", r, debugstr_w(szDBPath));
221  return ERROR_FUNCTION_FAILED;
222  }
223 
224  r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
225  if( FAILED( r ) )
226  {
227  FIXME("Failed to stat storage\n");
228  goto end;
229  }
230 
231  if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
232  !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) &&
233  !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
234  {
235  ERR("storage GUID is not a MSI database GUID %s\n",
236  debugstr_guid(&stat.clsid) );
237  goto end;
238  }
239 
240  if ( patch && !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
241  {
242  ERR("storage GUID is not the MSI patch GUID %s\n",
243  debugstr_guid(&stat.clsid) );
245  goto end;
246  }
247 
250  if( !db )
251  {
252  FIXME("Failed to allocate a handle\n");
253  goto end;
254  }
255 
256  if (!wcschr( save_path, '\\' ))
257  {
259  lstrcatW( path, L"\\" );
260  lstrcatW( path, save_path );
261  }
262  else
263  lstrcpyW( path, save_path );
264 
265  db->path = strdupW( path );
268 
269  if( TRACE_ON( msi ) )
270  enum_stream_names( stg );
271 
272  db->storage = stg;
273  db->mode = mode;
274  if (created)
275  db->deletefile = strdupW( szDBPath );
276  list_init( &db->tables );
277  list_init( &db->transforms );
278 
280  if( !db->strings )
281  goto end;
282 
283  ret = ERROR_SUCCESS;
284 
285  msiobj_addref( &db->hdr );
286  IStorage_AddRef( stg );
287  *pdb = db;
288 
289 end:
290  if( db )
291  msiobj_release( &db->hdr );
292  if( stg )
293  IStorage_Release( stg );
294 
295  return ret;
296 }
297 
299 {
300  MSIDATABASE *db;
301  UINT ret;
302 
303  TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
304 
305  ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
306  if( ret == ERROR_SUCCESS )
307  {
308  *phDB = alloc_msihandle( &db->hdr );
309  if (! *phDB)
311  msiobj_release( &db->hdr );
312  }
313 
314  return ret;
315 }
316 
317 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
318 {
320  LPWSTR szwDBPath = NULL, szwPersist = NULL;
321 
322  TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
323 
324  if( szDBPath )
325  {
326  szwDBPath = strdupAtoW( szDBPath );
327  if( !szwDBPath )
328  goto end;
329  }
330 
331  if( !IS_INTMSIDBOPEN(szPersist) )
332  {
333  szwPersist = strdupAtoW( szPersist );
334  if( !szwPersist )
335  goto end;
336  }
337  else
338  szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
339 
340  r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
341 
342 end:
343  if( !IS_INTMSIDBOPEN(szPersist) )
344  msi_free( szwPersist );
345  msi_free( szwDBPath );
346 
347  return r;
348 }
349 
351 {
352  HANDLE file;
353  LPSTR data = NULL;
354  LPWSTR wdata = NULL;
355  DWORD read, size = 0;
356 
358  if (file == INVALID_HANDLE_VALUE)
359  return NULL;
360 
361  size = GetFileSize( file, NULL );
362  if (!(data = msi_alloc( size ))) goto done;
363 
364  if (!ReadFile( file, data, size, &read, NULL ) || read != size) goto done;
365 
366  while (!data[size - 1]) size--;
367  *len = MultiByteToWideChar( CP_ACP, 0, data, size, NULL, 0 );
368  if ((wdata = msi_alloc( (*len + 1) * sizeof(WCHAR) )))
369  {
370  MultiByteToWideChar( CP_ACP, 0, data, size, wdata, *len );
371  wdata[*len] = 0;
372  }
373 
374 done:
375  CloseHandle( file );
376  msi_free( data );
377  return wdata;
378 }
379 
380 static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries, DWORD *len)
381 {
382  LPWSTR ptr = *line, save;
383  DWORD i, count = 1, chars_left = *len;
384 
385  *entries = NULL;
386 
387  /* stay on this line */
388  while (chars_left && *ptr != '\n')
389  {
390  /* entries are separated by tabs */
391  if (*ptr == '\t')
392  count++;
393 
394  ptr++;
395  chars_left--;
396  }
397 
398  *entries = msi_alloc(count * sizeof(LPWSTR));
399  if (!*entries)
400  return;
401 
402  /* store pointers into the data */
403  chars_left = *len;
404  for (i = 0, ptr = *line; i < count; i++)
405  {
406  while (chars_left && *ptr == '\r')
407  {
408  ptr++;
409  chars_left--;
410  }
411  save = ptr;
412 
413  while (chars_left && *ptr != '\t' && *ptr != '\n' && *ptr != '\r')
414  {
415  if (!*ptr) *ptr = '\n'; /* convert embedded nulls to \n */
416  if (ptr > *line && *ptr == '\x19' && *(ptr - 1) == '\x11')
417  {
418  *ptr = '\n';
419  *(ptr - 1) = '\r';
420  }
421  ptr++;
422  chars_left--;
423  }
424 
425  /* NULL-separate the data */
426  if (*ptr == '\n' || *ptr == '\r')
427  {
428  while (chars_left && (*ptr == '\n' || *ptr == '\r'))
429  {
430  *(ptr++) = 0;
431  chars_left--;
432  }
433  }
434  else if (*ptr)
435  {
436  *(ptr++) = 0;
437  chars_left--;
438  }
439  (*entries)[i] = save;
440  }
441 
442  /* move to the next line if there's more, else EOF */
443  *line = ptr;
444  *len = chars_left;
445  if (num_entries)
446  *num_entries = count;
447 }
448 
450 {
451  LPWSTR prelude;
452  DWORD size;
453 
454  size = ARRAY_SIZE(L"CREATE TABLE `%s` ( ") + lstrlenW(table) - 2;
455  prelude = msi_alloc(size * sizeof(WCHAR));
456  if (!prelude)
457  return NULL;
458 
459  swprintf(prelude, size, L"CREATE TABLE `%s` ( ", table);
460  return prelude;
461 }
462 
463 static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns)
464 {
465  LPWSTR columns, p;
466  LPCWSTR type;
467  DWORD sql_size = 1, i, len;
468  WCHAR expanded[128], *ptr;
469  WCHAR size[10], comma[2], extra[30];
470 
471  columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
472  if (!columns)
473  return NULL;
474 
475  for (i = 0; i < num_columns; i++)
476  {
477  type = NULL;
478  comma[1] = size[0] = extra[0] = '\0';
479 
480  if (i == num_columns - 1)
481  comma[0] = '\0';
482  else
483  comma[0] = ',';
484 
485  ptr = &types[i][1];
486  len = wcstol(ptr, NULL, 10);
487  extra[0] = '\0';
488 
489  switch (types[i][0])
490  {
491  case 'l':
492  lstrcpyW(extra, L" NOT NULL");
493  /* fall through */
494  case 'L':
495  lstrcatW(extra, L" LOCALIZABLE");
496  type = L"CHAR";
497  swprintf(size, ARRAY_SIZE(size), L"(%s)", ptr);
498  break;
499  case 's':
500  lstrcpyW(extra, L" NOT NULL");
501  /* fall through */
502  case 'S':
503  type = L"CHAR";
504  swprintf(size, ARRAY_SIZE(size), L"(%s)", ptr);
505  break;
506  case 'i':
507  lstrcpyW(extra, L" NOT NULL");
508  /* fall through */
509  case 'I':
510  if (len <= 2)
511  type = L"INT";
512  else if (len == 4)
513  type = L"LONG";
514  else
515  {
516  WARN("invalid int width %lu\n", len);
517  msi_free(columns);
518  return NULL;
519  }
520  break;
521  case 'v':
522  lstrcpyW(extra, L" NOT NULL");
523  /* fall through */
524  case 'V':
525  type = L"OBJECT";
526  break;
527  default:
528  ERR("Unknown type: %c\n", types[i][0]);
529  msi_free(columns);
530  return NULL;
531  }
532 
533  swprintf(expanded, ARRAY_SIZE(expanded), L"`%s` %s%s%s%s ", columns_data[i], type, size, extra, comma);
534  sql_size += lstrlenW(expanded);
535 
536  p = msi_realloc(columns, sql_size * sizeof(WCHAR));
537  if (!p)
538  {
539  msi_free(columns);
540  return NULL;
541  }
542  columns = p;
543 
544  lstrcatW(columns, expanded);
545  }
546 
547  return columns;
548 }
549 
550 static LPWSTR msi_build_createsql_postlude(LPWSTR *primary_keys, DWORD num_keys)
551 {
552  LPWSTR postlude, keys, ptr;
553  DWORD size, i;
554 
555  for (i = 0, size = 1; i < num_keys; i++)
556  size += lstrlenW(L"`%s`, ") + lstrlenW(primary_keys[i]) - 2;
557 
558  keys = msi_alloc(size * sizeof(WCHAR));
559  if (!keys)
560  return NULL;
561 
562  for (i = 0, ptr = keys; i < num_keys; i++)
563  {
564  ptr += swprintf(ptr, size - (ptr - keys), L"`%s`, ", primary_keys[i]);
565  }
566 
567  /* remove final ', ' */
568  *(ptr - 2) = '\0';
569 
570  size = lstrlenW(L"PRIMARY KEY %s)") + size - 1;
571  postlude = msi_alloc(size * sizeof(WCHAR));
572  if (!postlude)
573  goto done;
574 
575  swprintf(postlude, size, L"PRIMARY KEY %s)", keys);
576 
577 done:
578  msi_free(keys);
579  return postlude;
580 }
581 
582 static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
583 {
585  DWORD size;
586  MSIQUERY *view;
587  LPWSTR create_sql = NULL;
588  LPWSTR prelude, columns_sql, postlude;
589 
590  prelude = msi_build_createsql_prelude(labels[0]);
591  columns_sql = msi_build_createsql_columns(columns, types, num_columns);
592  postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */
593 
594  if (!prelude || !columns_sql || !postlude)
595  goto done;
596 
597  size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1;
598  create_sql = msi_alloc(size * sizeof(WCHAR));
599  if (!create_sql)
600  goto done;
601 
602  lstrcpyW(create_sql, prelude);
603  lstrcatW(create_sql, columns_sql);
604  lstrcatW(create_sql, postlude);
605 
606  r = MSI_DatabaseOpenViewW( db, create_sql, &view );
607  if (r != ERROR_SUCCESS)
608  goto done;
609 
612  msiobj_release(&view->hdr);
613 
614 done:
615  msi_free(prelude);
616  msi_free(columns_sql);
617  msi_free(postlude);
618  msi_free(create_sql);
619  return r;
620 }
621 
623 {
624  DWORD len;
626 
627  len = lstrlenW(path) + lstrlenW(name) + 1;
628  fullname = msi_alloc(len*sizeof(WCHAR));
629  if (!fullname)
630  return NULL;
631 
632  lstrcpyW( fullname, path );
633 
634  /* chop off extension from path */
635  ptr = wcsrchr(fullname, '.');
636  if (!ptr)
637  {
638  msi_free (fullname);
639  return NULL;
640  }
641  *ptr++ = '\\';
642  lstrcpyW( ptr, name );
643  return fullname;
644 }
645 
646 static UINT construct_record(DWORD num_columns, LPWSTR *types,
647  LPWSTR *data, LPWSTR path, MSIRECORD **rec)
648 {
649  UINT i;
650 
651  *rec = MSI_CreateRecord(num_columns);
652  if (!*rec)
653  return ERROR_OUTOFMEMORY;
654 
655  for (i = 0; i < num_columns; i++)
656  {
657  switch (types[i][0])
658  {
659  case 'L': case 'l': case 'S': case 's':
660  MSI_RecordSetStringW(*rec, i + 1, data[i]);
661  break;
662  case 'I': case 'i':
663  if (*data[i])
664  MSI_RecordSetInteger(*rec, i + 1, wcstol(data[i], NULL, 10));
665  break;
666  case 'V': case 'v':
667  if (*data[i])
668  {
669  UINT r;
671  if (!file)
672  return ERROR_FUNCTION_FAILED;
673 
674  r = MSI_RecordSetStreamFromFileW(*rec, i + 1, file);
675  msi_free (file);
676  if (r != ERROR_SUCCESS)
677  return ERROR_FUNCTION_FAILED;
678  }
679  break;
680  default:
681  ERR("Unhandled column type: %c\n", types[i][0]);
682  msiobj_release(&(*rec)->hdr);
683  return ERROR_FUNCTION_FAILED;
684  }
685  }
686 
687  return ERROR_SUCCESS;
688 }
689 
691  LPWSTR *labels, LPWSTR **records,
692  int num_columns, int num_records,
693  LPWSTR path)
694 {
695  UINT r;
696  int i;
697  MSIQUERY *view;
698  MSIRECORD *rec;
699 
700  r = MSI_OpenQuery(db, &view, L"SELECT * FROM `%s`", labels[0]);
701  if (r != ERROR_SUCCESS)
702  return r;
703 
704  while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
705  {
707  msiobj_release(&rec->hdr);
708  if (r != ERROR_SUCCESS)
709  goto done;
710  }
711 
712  for (i = 0; i < num_records; i++)
713  {
714  r = construct_record(num_columns, types, records[i], path, &rec);
715  if (r != ERROR_SUCCESS)
716  goto done;
717 
719  if (r != ERROR_SUCCESS)
720  {
721  msiobj_release(&rec->hdr);
722  goto done;
723  }
724 
725  msiobj_release(&rec->hdr);
726  }
727 
728 done:
729  msiobj_release(&view->hdr);
730  return r;
731 }
732 
734 {
735  UINT r;
736  DWORD len, i, num_labels, num_types, num_columns, num_records = 0;
737  WCHAR **columns, **types, **labels, *path, *ptr, *data, ***records = NULL, ***temp_records;
738 
739  TRACE("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
740 
741  if (!folder || !file)
743 
744  len = lstrlenW(folder) + lstrlenW(L"\\") + lstrlenW(file) + 1;
745  path = msi_alloc( len * sizeof(WCHAR) );
746  if (!path)
747  return ERROR_OUTOFMEMORY;
748 
749  lstrcpyW( path, folder );
750  lstrcatW( path, L"\\" );
751  lstrcatW( path, file );
752 
754  if (!data)
755  {
756  msi_free(path);
757  return ERROR_FUNCTION_FAILED;
758  }
759 
760  ptr = data;
761  msi_parse_line( &ptr, &columns, &num_columns, &len );
762  msi_parse_line( &ptr, &types, &num_types, &len );
763  msi_parse_line( &ptr, &labels, &num_labels, &len );
764 
765  if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
766  num_types == 2 && !wcscmp( types[1], L"_ForceCodepage" ))
767  {
769  goto done;
770  }
771 
772  if (num_columns != num_types)
773  {
775  goto done;
776  }
777 
778  records = msi_alloc(sizeof(WCHAR **));
779  if (!records)
780  {
782  goto done;
783  }
784 
785  /* read in the table records */
786  while (len)
787  {
788  msi_parse_line( &ptr, &records[num_records], NULL, &len );
789 
790  num_records++;
791  temp_records = msi_realloc(records, (num_records + 1) * sizeof(WCHAR **));
792  if (!temp_records)
793  {
795  goto done;
796  }
797  records = temp_records;
798  }
799 
800  if (!wcscmp(labels[0], L"_SummaryInformation"))
801  {
802  r = msi_add_suminfo( db, records, num_records, num_columns );
803  if (r != ERROR_SUCCESS)
804  {
806  goto done;
807  }
808  }
809  else
810  {
811  if (!TABLE_Exists(db, labels[0]))
812  {
813  r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns );
814  if (r != ERROR_SUCCESS)
815  {
817  goto done;
818  }
819  }
820 
821  r = msi_add_records_to_table( db, columns, types, labels, records, num_columns, num_records, path );
822  }
823 
824 done:
825  msi_free(path);
826  msi_free(data);
827  msi_free(columns);
828  msi_free(types);
829  msi_free(labels);
830 
831  for (i = 0; i < num_records; i++)
832  msi_free(records[i]);
833 
834  msi_free(records);
835  return r;
836 }
837 
838 UINT WINAPI MsiDatabaseImportW( MSIHANDLE handle, const WCHAR *szFolder, const WCHAR *szFilename )
839 {
840  MSIDATABASE *db;
841  UINT r;
842 
843  TRACE( "%lu %s %s\n", handle, debugstr_w(szFolder), debugstr_w(szFilename) );
844 
846  return ERROR_INVALID_HANDLE;
847 
848  r = MSI_DatabaseImport( db, szFolder, szFilename );
849  msiobj_release( &db->hdr );
850  return r;
851 }
852 
853 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle, const char *szFolder, const char *szFilename )
854 {
855  WCHAR *path = NULL, *file = NULL;
857 
858  TRACE( "%lu %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename) );
859 
860  if( szFolder )
861  {
862  path = strdupAtoW( szFolder );
863  if( !path )
864  goto end;
865  }
866 
867  if( szFilename )
868  {
869  file = strdupAtoW( szFilename );
870  if( !file )
871  goto end;
872  }
873 
875 
876 end:
877  msi_free( path );
878  msi_free( file );
879 
880  return r;
881 }
882 
884 {
885  char *buffer;
886  BOOL ret;
887  DWORD sz = 0x100;
888  UINT r;
889 
890  buffer = msi_alloc( sz );
891  if (!buffer)
892  return ERROR_OUTOFMEMORY;
893 
894  r = MSI_RecordGetStringA( row, field, buffer, &sz );
895  if (r == ERROR_MORE_DATA)
896  {
897  char *tmp;
898 
899  sz++; /* leave room for NULL terminator */
900  tmp = msi_realloc( buffer, sz );
901  if (!tmp)
902  {
903  msi_free( buffer );
904  return ERROR_OUTOFMEMORY;
905  }
906  buffer = tmp;
907 
908  r = MSI_RecordGetStringA( row, field, buffer, &sz );
909  if (r != ERROR_SUCCESS)
910  {
911  msi_free( buffer );
912  return r;
913  }
914  }
915  else if (r != ERROR_SUCCESS)
916  {
917  msi_free( buffer );
918  return r;
919  }
920 
921  ret = WriteFile( handle, buffer, sz, &sz, NULL );
922  msi_free( buffer );
924 }
925 
927 {
929  DWORD sz, read_size, write_size;
930  char buffer[1024];
931  HANDLE file;
932  UINT len, r;
933 
934  sz = ARRAY_SIZE( stream );
935  r = MSI_RecordGetStringW( row, start, stream, &sz );
936  if (r != ERROR_SUCCESS)
937  return r;
938 
939  len = sz + lstrlenW( folder ) + lstrlenW( table ) + ARRAY_SIZE( L"%s\\%s" ) + 1;
940  if (!(path = msi_alloc( len * sizeof(WCHAR) )))
941  return ERROR_OUTOFMEMORY;
942 
943  len = swprintf( path, len, L"%s\\%s", folder, table );
945  {
946  msi_free( path );
947  return ERROR_FUNCTION_FAILED;
948  }
949 
950  path[len++] = '\\';
951  lstrcpyW( path + len, stream );
954  msi_free( path );
955  if (file == INVALID_HANDLE_VALUE)
956  return ERROR_FUNCTION_FAILED;
957 
958  read_size = sizeof(buffer);
959  while (read_size == sizeof(buffer))
960  {
961  r = MSI_RecordReadStream( row, field, buffer, &read_size );
962  if (r != ERROR_SUCCESS)
963  {
964  CloseHandle( file );
965  return r;
966  }
967  if (!WriteFile( file, buffer, read_size, &write_size, NULL ) || read_size != write_size)
968  {
969  CloseHandle( file );
970  return ERROR_WRITE_FAULT;
971  }
972  }
973  CloseHandle( file );
974  return r;
975 }
976 
978 {
980  const WCHAR *folder;
981  const WCHAR *table;
982 };
983 
985 {
987  UINT i, count, r = ERROR_SUCCESS;
988  const char *sep;
989  DWORD sz;
990 
992  for (i = start; i <= count; i++)
993  {
994  r = msi_export_field( handle, row, i );
995  if (r == ERROR_INVALID_PARAMETER)
996  {
998  if (r != ERROR_SUCCESS)
999  return r;
1000 
1001  /* exporting a binary stream, repeat the "Name" field */
1003  if (r != ERROR_SUCCESS)
1004  return r;
1005  }
1006  else if (r != ERROR_SUCCESS)
1007  return r;
1008 
1009  sep = (i < count) ? "\t" : "\r\n";
1010  if (!WriteFile( handle, sep, strlen(sep), &sz, NULL ))
1011  return ERROR_FUNCTION_FAILED;
1012  }
1013  return r;
1014 }
1015 
1017 {
1018  return msi_export_record( arg, row, 1 );
1019 }
1020 
1022 {
1023  static const char fmt[] = "\r\n\r\n%u\t_ForceCodepage\r\n";
1024  char data[sizeof(fmt) + 10];
1025  DWORD sz = sprintf( data, fmt, codepage );
1026 
1027  if (!WriteFile(handle, data, sz, &sz, NULL))
1028  return ERROR_FUNCTION_FAILED;
1029 
1030  return ERROR_SUCCESS;
1031 }
1032 
1034 {
1035  static const char header[] = "PropertyId\tValue\r\n"
1036  "i2\tl255\r\n"
1037  "_SummaryInformation\tPropertyId\r\n";
1038  DWORD sz = ARRAY_SIZE(header) - 1;
1039 
1040  if (!WriteFile(handle, header, sz, &sz, NULL))
1041  return ERROR_WRITE_FAULT;
1042 
1043  return msi_export_suminfo( db, handle );
1044 }
1045 
1047 {
1048  MSIRECORD *rec = NULL;
1049  MSIQUERY *view = NULL;
1050  WCHAR *filename;
1051  HANDLE handle;
1052  UINT len, r;
1053 
1054  TRACE("%p %s %s %s\n", db, debugstr_w(table),
1056 
1057  if (!folder || !file)
1058  return ERROR_INVALID_PARAMETER;
1059 
1060  len = lstrlenW(folder) + lstrlenW(file) + 2;
1061  filename = msi_alloc(len * sizeof (WCHAR));
1062  if (!filename)
1063  return ERROR_OUTOFMEMORY;
1064 
1065  lstrcpyW( filename, folder );
1066  lstrcatW( filename, L"\\" );
1067  lstrcatW( filename, file );
1068 
1071  msi_free( filename );
1073  return ERROR_FUNCTION_FAILED;
1074 
1075  if (!wcscmp( table, L"_ForceCodepage" ))
1076  {
1079  goto done;
1080  }
1081 
1082  if (!wcscmp( table, L"_SummaryInformation" ))
1083  {
1085  goto done;
1086  }
1087 
1088  r = MSI_OpenQuery( db, &view, L"SELECT * FROM %s", table );
1089  if (r == ERROR_SUCCESS)
1090  {
1092 
1093  /* write out row 1, the column names */
1095  if (r == ERROR_SUCCESS)
1096  {
1097  msi_export_record( &row_export_info, rec, 1 );
1098  msiobj_release( &rec->hdr );
1099  }
1100 
1101  /* write out row 2, the column types */
1103  if (r == ERROR_SUCCESS)
1104  {
1105  msi_export_record( &row_export_info, rec, 1 );
1106  msiobj_release( &rec->hdr );
1107  }
1108 
1109  /* write out row 3, the table name + keys */
1110  r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1111  if (r == ERROR_SUCCESS)
1112  {
1113  MSI_RecordSetStringW( rec, 0, table );
1114  msi_export_record( &row_export_info, rec, 0 );
1115  msiobj_release( &rec->hdr );
1116  }
1117 
1118  /* write out row 4 onwards, the data */
1120  msiobj_release( &view->hdr );
1121  }
1122 
1123 done:
1124  CloseHandle( handle );
1125  return r;
1126 }
1127 
1128 /***********************************************************************
1129  * MsiExportDatabaseW [MSI.@]
1130  *
1131  * Writes a file containing the table data as tab separated ASCII.
1132  *
1133  * The format is as follows:
1134  *
1135  * row1 : colname1 <tab> colname2 <tab> .... colnameN <cr> <lf>
1136  * row2 : coltype1 <tab> coltype2 <tab> .... coltypeN <cr> <lf>
1137  * row3 : tablename <tab> key1 <tab> key2 <tab> ... keyM <cr> <lf>
1138  *
1139  * Followed by the data, starting at row 1 with one row per line
1140  *
1141  * row4 : data <tab> data <tab> data <tab> ... data <cr> <lf>
1142  */
1143 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, const WCHAR *szTable, const WCHAR *szFolder, const WCHAR *szFilename )
1144 {
1145  MSIDATABASE *db;
1146  UINT r;
1147 
1148  TRACE( "%lu %s %s %s\n", handle, debugstr_w(szTable), debugstr_w(szFolder), debugstr_w(szFilename) );
1149 
1151  return ERROR_INVALID_HANDLE;
1152 
1153  r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
1154  msiobj_release( &db->hdr );
1155  return r;
1156 }
1157 
1158 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, const char *szTable, const char *szFolder, const char *szFilename )
1159 {
1160  WCHAR *path = NULL, *file = NULL, *table = NULL;
1162 
1163  TRACE( "%lu %s %s %s\n", handle, debugstr_a(szTable), debugstr_a(szFolder), debugstr_a(szFilename) );
1164 
1165  if( szTable )
1166  {
1167  table = strdupAtoW( szTable );
1168  if( !table )
1169  goto end;
1170  }
1171 
1172  if( szFolder )
1173  {
1174  path = strdupAtoW( szFolder );
1175  if( !path )
1176  goto end;
1177  }
1178 
1179  if( szFilename )
1180  {
1181  file = strdupAtoW( szFilename );
1182  if( !file )
1183  goto end;
1184  }
1185 
1187 
1188 end:
1189  msi_free( table );
1190  msi_free( path );
1191  msi_free( file );
1192 
1193  return r;
1194 }
1195 
1196 UINT WINAPI MsiDatabaseMergeA( MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge, const char *szTableName )
1197 {
1198  UINT r;
1199  WCHAR *table;
1200 
1201  TRACE("%lu, %lu, %s\n", hDatabase, hDatabaseMerge, debugstr_a(szTableName) );
1202 
1203  table = strdupAtoW(szTableName);
1204  r = MsiDatabaseMergeW(hDatabase, hDatabaseMerge, table);
1205 
1206  msi_free(table);
1207  return r;
1208 }
1209 
1210 typedef struct _tagMERGETABLE
1211 {
1212  struct list entry;
1213  struct list rows;
1222 } MERGETABLE;
1223 
1224 typedef struct _tagMERGEROW
1225 {
1226  struct list entry;
1228 } MERGEROW;
1229 
1230 typedef struct _tagMERGEDATA
1231 {
1236  struct list *tabledata;
1237 } MERGEDATA;
1238 
1239 static BOOL merge_type_match(LPCWSTR type1, LPCWSTR type2)
1240 {
1241  if (((type1[0] == 'l') || (type1[0] == 's')) &&
1242  ((type2[0] == 'l') || (type2[0] == 's')))
1243  return TRUE;
1244 
1245  if (((type1[0] == 'L') || (type1[0] == 'S')) &&
1246  ((type2[0] == 'L') || (type2[0] == 'S')))
1247  return TRUE;
1248 
1249  return !wcscmp( type1, type2 );
1250 }
1251 
1252 static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
1253 {
1254  MSIRECORD *dbrec, *mergerec;
1255  UINT r, i, count;
1256 
1257  r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_NAMES, &dbrec);
1258  if (r != ERROR_SUCCESS)
1259  return r;
1260 
1261  r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_NAMES, &mergerec);
1262  if (r != ERROR_SUCCESS)
1263  {
1264  msiobj_release(&dbrec->hdr);
1265  return r;
1266  }
1267 
1268  count = MSI_RecordGetFieldCount(dbrec);
1269  for (i = 1; i <= count; i++)
1270  {
1271  if (!MSI_RecordGetString(mergerec, i))
1272  break;
1273 
1274  if (wcscmp( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
1275  {
1277  goto done;
1278  }
1279  }
1280 
1281  msiobj_release(&dbrec->hdr);
1282  msiobj_release(&mergerec->hdr);
1283  dbrec = mergerec = NULL;
1284 
1285  r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_TYPES, &dbrec);
1286  if (r != ERROR_SUCCESS)
1287  return r;
1288 
1289  r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_TYPES, &mergerec);
1290  if (r != ERROR_SUCCESS)
1291  {
1292  msiobj_release(&dbrec->hdr);
1293  return r;
1294  }
1295 
1296  count = MSI_RecordGetFieldCount(dbrec);
1297  for (i = 1; i <= count; i++)
1298  {
1299  if (!MSI_RecordGetString(mergerec, i))
1300  break;
1301 
1302  if (!merge_type_match(MSI_RecordGetString(dbrec, i),
1303  MSI_RecordGetString(mergerec, i)))
1304  {
1306  break;
1307  }
1308  }
1309 
1310 done:
1311  msiobj_release(&dbrec->hdr);
1312  msiobj_release(&mergerec->hdr);
1313 
1314  return r;
1315 }
1316 
1318  LPCWSTR table)
1319 {
1320  MSIRECORD *dbrec, *mergerec = NULL;
1321  UINT r, i, count;
1322 
1323  r = MSI_DatabaseGetPrimaryKeys(db, table, &dbrec);
1324  if (r != ERROR_SUCCESS)
1325  return r;
1326 
1327  r = MSI_DatabaseGetPrimaryKeys(mergedb, table, &mergerec);
1328  if (r != ERROR_SUCCESS)
1329  goto done;
1330 
1331  count = MSI_RecordGetFieldCount(dbrec);
1332  if (count != MSI_RecordGetFieldCount(mergerec))
1333  {
1335  goto done;
1336  }
1337 
1338  for (i = 1; i <= count; i++)
1339  {
1340  if (wcscmp( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
1341  {
1343  goto done;
1344  }
1345  }
1346 
1347 done:
1348  msiobj_release(&dbrec->hdr);
1349  msiobj_release(&mergerec->hdr);
1350 
1351  return r;
1352 }
1353 
1355 {
1356  MSIRECORD *colnames;
1357  LPWSTR str, val;
1358  UINT r, i = 0;
1359  DWORD sz = 0;
1360  int cmp;
1361 
1363  if (r != ERROR_SUCCESS)
1364  return NULL;
1365 
1366  do
1367  {
1368  str = msi_dup_record_field(colnames, ++i);
1369  cmp = wcscmp( key, str );
1370  msi_free(str);
1371  } while (cmp);
1372 
1373  msiobj_release(&colnames->hdr);
1374 
1375  r = MSI_RecordGetStringW(rec, i, NULL, &sz);
1376  if (r != ERROR_SUCCESS)
1377  return NULL;
1378  sz++;
1379 
1380  if (MSI_RecordGetString(rec, i)) /* check record field is a string */
1381  {
1382  /* quote string record fields */
1383  sz += 2;
1384  val = msi_alloc(sz * sizeof(WCHAR));
1385  if (!val)
1386  return NULL;
1387 
1388  lstrcpyW(val, L"'");
1389  r = MSI_RecordGetStringW(rec, i, val + 1, &sz);
1390  lstrcpyW(val + 1 + sz, L"'");
1391  }
1392  else
1393  {
1394  /* do not quote integer record fields */
1395  val = msi_alloc(sz * sizeof(WCHAR));
1396  if (!val)
1397  return NULL;
1398 
1399  r = MSI_RecordGetStringW(rec, i, val, &sz);
1400  }
1401 
1402  if (r != ERROR_SUCCESS)
1403  {
1404  ERR("failed to get string!\n");
1405  msi_free(val);
1406  return NULL;
1407  }
1408 
1409  return val;
1410 }
1411 
1413  LPWSTR table, MSIRECORD *rec)
1414 {
1415  LPWSTR query = NULL, clause = NULL, val;
1416  LPCWSTR setptr, key;
1417  DWORD size, oldsize;
1418  MSIRECORD *keys;
1419  UINT r, i, count;
1420 
1422  if (r != ERROR_SUCCESS)
1423  return NULL;
1424 
1425  clause = msi_alloc_zero(sizeof(WCHAR));
1426  if (!clause)
1427  goto done;
1428 
1429  size = 1;
1431  for (i = 1; i <= count; i++)
1432  {
1433  key = MSI_RecordGetString(keys, i);
1434  val = get_key_value(view, key, rec);
1435 
1436  if (i == count)
1437  setptr = L"`%s` = %s ";
1438  else
1439  setptr = L"`%s` = %s AND ";
1440 
1441  oldsize = size;
1442  size += lstrlenW(setptr) + lstrlenW(key) + lstrlenW(val) - 4;
1443  clause = msi_realloc(clause, size * sizeof (WCHAR));
1444  if (!clause)
1445  {
1446  msi_free(val);
1447  goto done;
1448  }
1449 
1450  swprintf(clause + oldsize - 1, size - (oldsize - 1), setptr, key, val);
1451  msi_free(val);
1452  }
1453 
1454  size = lstrlenW(L"SELECT * FROM `%s` WHERE %s") + lstrlenW(table) + lstrlenW(clause) + 1;
1455  query = msi_alloc(size * sizeof(WCHAR));
1456  if (!query)
1457  goto done;
1458 
1459  swprintf(query, size, L"SELECT * FROM `%s` WHERE %s", table, clause);
1460 
1461 done:
1462  msi_free(clause);
1463  msiobj_release(&keys->hdr);
1464  return query;
1465 }
1466 
1468 {
1469  MERGEDATA *data = param;
1470  MERGETABLE *table = data->curtable;
1471  MERGEROW *mergerow;
1472  MSIQUERY *dbview = NULL;
1473  MSIRECORD *row = NULL;
1474  LPWSTR query = NULL;
1475  UINT r = ERROR_SUCCESS;
1476 
1477  if (TABLE_Exists(data->db, table->name))
1478  {
1479  query = create_diff_row_query(data->merge, data->curview, table->name, rec);
1480  if (!query)
1481  return ERROR_OUTOFMEMORY;
1482 
1483  r = MSI_DatabaseOpenViewW(data->db, query, &dbview);
1484  if (r != ERROR_SUCCESS)
1485  goto done;
1486 
1487  r = MSI_ViewExecute(dbview, NULL);
1488  if (r != ERROR_SUCCESS)
1489  goto done;
1490 
1491  r = MSI_ViewFetch(dbview, &row);
1492  if (r == ERROR_SUCCESS && !MSI_RecordsAreEqual(rec, row))
1493  {
1494  table->numconflicts++;
1495  goto done;
1496  }
1497  else if (r != ERROR_NO_MORE_ITEMS)
1498  goto done;
1499 
1500  r = ERROR_SUCCESS;
1501  }
1502 
1503  mergerow = msi_alloc(sizeof(MERGEROW));
1504  if (!mergerow)
1505  {
1506  r = ERROR_OUTOFMEMORY;
1507  goto done;
1508  }
1509 
1510  mergerow->data = MSI_CloneRecord(rec);
1511  if (!mergerow->data)
1512  {
1513  r = ERROR_OUTOFMEMORY;
1514  msi_free(mergerow);
1515  goto done;
1516  }
1517 
1518  list_add_tail(&table->rows, &mergerow->entry);
1519 
1520 done:
1521  msi_free(query);
1522  msiobj_release(&row->hdr);
1523  msiobj_release(&dbview->hdr);
1524  return r;
1525 }
1526 
1527 static UINT msi_get_table_labels(MSIDATABASE *db, LPCWSTR table, LPWSTR **labels, DWORD *numlabels)
1528 {
1529  UINT r, i, count;
1530  MSIRECORD *prec = NULL;
1531 
1532  r = MSI_DatabaseGetPrimaryKeys(db, table, &prec);
1533  if (r != ERROR_SUCCESS)
1534  return r;
1535 
1537  *numlabels = count + 1;
1538  *labels = msi_alloc((*numlabels)*sizeof(LPWSTR));
1539  if (!*labels)
1540  {
1541  r = ERROR_OUTOFMEMORY;
1542  goto end;
1543  }
1544 
1545  (*labels)[0] = strdupW(table);
1546  for (i=1; i<=count; i++ )
1547  {
1548  (*labels)[i] = strdupW(MSI_RecordGetString(prec, i));
1549  }
1550 
1551 end:
1552  msiobj_release( &prec->hdr );
1553  return r;
1554 }
1555 
1556 static UINT msi_get_query_columns(MSIQUERY *query, LPWSTR **columns, DWORD *numcolumns)
1557 {
1558  UINT r, i, count;
1559  MSIRECORD *prec = NULL;
1560 
1562  if (r != ERROR_SUCCESS)
1563  return r;
1564 
1566  *columns = msi_alloc(count*sizeof(LPWSTR));
1567  if (!*columns)
1568  {
1569  r = ERROR_OUTOFMEMORY;
1570  goto end;
1571  }
1572 
1573  for (i=1; i<=count; i++ )
1574  {
1575  (*columns)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1576  }
1577 
1578  *numcolumns = count;
1579 
1580 end:
1581  msiobj_release( &prec->hdr );
1582  return r;
1583 }
1584 
1586 {
1587  UINT r, i, count;
1588  MSIRECORD *prec = NULL;
1589 
1591  if (r != ERROR_SUCCESS)
1592  return r;
1593 
1595  *types = msi_alloc(count*sizeof(LPWSTR));
1596  if (!*types)
1597  {
1598  r = ERROR_OUTOFMEMORY;
1599  goto end;
1600  }
1601 
1602  *numtypes = count;
1603  for (i=1; i<=count; i++ )
1604  {
1605  (*types)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1606  }
1607 
1608 end:
1609  msiobj_release( &prec->hdr );
1610  return r;
1611 }
1612 
1614 {
1615  struct list *item, *cursor;
1616 
1618  {
1620 
1621  list_remove(&row->entry);
1622  msiobj_release(&row->data->hdr);
1623  msi_free(row);
1624  }
1625 }
1626 
1628 {
1629  UINT i;
1630 
1631  if (table->labels != NULL)
1632  {
1633  for (i = 0; i < table->numlabels; i++)
1634  msi_free(table->labels[i]);
1635 
1636  msi_free(table->labels);
1637  }
1638 
1639  if (table->columns != NULL)
1640  {
1641  for (i = 0; i < table->numcolumns; i++)
1642  msi_free(table->columns[i]);
1643 
1645  }
1646 
1647  if (table->types != NULL)
1648  {
1649  for (i = 0; i < table->numtypes; i++)
1650  msi_free(table->types[i]);
1651 
1652  msi_free(table->types);
1653  }
1654 
1655  msi_free(table->name);
1657 
1658  msi_free(table);
1659 }
1660 
1662 {
1663  UINT r;
1664  MERGETABLE *table;
1665  MSIQUERY *mergeview = NULL;
1666 
1667  table = msi_alloc_zero(sizeof(MERGETABLE));
1668  if (!table)
1669  {
1670  *ptable = NULL;
1671  return ERROR_OUTOFMEMORY;
1672  }
1673 
1674  r = msi_get_table_labels(db, name, &table->labels, &table->numlabels);
1675  if (r != ERROR_SUCCESS)
1676  goto err;
1677 
1678  r = MSI_OpenQuery(db, &mergeview, L"SELECT * FROM `%s`", name);
1679  if (r != ERROR_SUCCESS)
1680  goto err;
1681 
1682  r = msi_get_query_columns(mergeview, &table->columns, &table->numcolumns);
1683  if (r != ERROR_SUCCESS)
1684  goto err;
1685 
1686  r = msi_get_query_types(mergeview, &table->types, &table->numtypes);
1687  if (r != ERROR_SUCCESS)
1688  goto err;
1689 
1690  list_init(&table->rows);
1691 
1692  table->name = strdupW(name);
1693  table->numconflicts = 0;
1694 
1695  msiobj_release(&mergeview->hdr);
1696  *ptable = table;
1697  return ERROR_SUCCESS;
1698 
1699 err:
1700  msiobj_release(&mergeview->hdr);
1702  *ptable = NULL;
1703  return r;
1704 }
1705 
1707 {
1708  MERGEDATA *data = param;
1709  MERGETABLE *table;
1710  MSIQUERY *dbview = NULL;
1711  MSIQUERY *mergeview = NULL;
1712  LPCWSTR name;
1713  UINT r;
1714 
1715  name = MSI_RecordGetString(rec, 1);
1716 
1717  r = MSI_OpenQuery(data->merge, &mergeview, L"SELECT * FROM `%s`", name);
1718  if (r != ERROR_SUCCESS)
1719  goto done;
1720 
1721  if (TABLE_Exists(data->db, name))
1722  {
1723  r = MSI_OpenQuery(data->db, &dbview, L"SELECT * FROM `%s`", name);
1724  if (r != ERROR_SUCCESS)
1725  goto done;
1726 
1727  r = merge_verify_colnames(dbview, mergeview);
1728  if (r != ERROR_SUCCESS)
1729  goto done;
1730 
1731  r = merge_verify_primary_keys(data->db, data->merge, name);
1732  if (r != ERROR_SUCCESS)
1733  goto done;
1734  }
1735 
1736  r = msi_get_merge_table(data->merge, name, &table);
1737  if (r != ERROR_SUCCESS)
1738  goto done;
1739 
1740  data->curtable = table;
1741  data->curview = mergeview;
1742  r = MSI_IterateRecords(mergeview, NULL, merge_diff_row, data);
1743  if (r != ERROR_SUCCESS)
1744  {
1746  goto done;
1747  }
1748 
1749  list_add_tail(data->tabledata, &table->entry);
1750 
1751 done:
1752  msiobj_release(&dbview->hdr);
1753  msiobj_release(&mergeview->hdr);
1754  return r;
1755 }
1756 
1758  struct list *tabledata)
1759 {
1760  MSIQUERY *view;
1761  MERGEDATA data;
1762  UINT r;
1763 
1764  r = MSI_DatabaseOpenViewW(merge, L"SELECT * FROM `_Tables`", &view);
1765  if (r != ERROR_SUCCESS)
1766  return r;
1767 
1768  data.db = db;
1769  data.merge = merge;
1770  data.tabledata = tabledata;
1772  msiobj_release(&view->hdr);
1773  return r;
1774 }
1775 
1777 {
1778  UINT r;
1779  MERGEROW *row;
1780  MSIVIEW *tv;
1781 
1782  if (!TABLE_Exists(db, table->name))
1783  {
1784  r = msi_add_table_to_db(db, table->columns, table->types,
1785  table->labels, table->numlabels, table->numcolumns);
1786  if (r != ERROR_SUCCESS)
1787  return ERROR_FUNCTION_FAILED;
1788  }
1789 
1791  {
1792  r = TABLE_CreateView(db, table->name, &tv);
1793  if (r != ERROR_SUCCESS)
1794  return r;
1795 
1796  r = tv->ops->insert_row(tv, row->data, -1, FALSE);
1797  tv->ops->delete(tv);
1798 
1799  if (r != ERROR_SUCCESS)
1800  return r;
1801  }
1802 
1803  return ERROR_SUCCESS;
1804 }
1805 
1807  LPWSTR table, DWORD numconflicts)
1808 {
1809  UINT r;
1810  MSIQUERY *view;
1811 
1812  if (!TABLE_Exists(db, error))
1813  {
1814  r = MSI_OpenQuery(db, &view, L"CREATE TABLE `%s` (`Table` CHAR(255) NOT NULL, `NumRowMergeConflicts` SHORT "
1815  "NOT NULL PRIMARY KEY `Table`)" , error);
1816  if (r != ERROR_SUCCESS)
1817  return r;
1818 
1819  r = MSI_ViewExecute(view, NULL);
1820  msiobj_release(&view->hdr);
1821  if (r != ERROR_SUCCESS)
1822  return r;
1823  }
1824 
1825  r = MSI_OpenQuery(db, &view, L"INSERT INTO `%s` (`Table`, `NumRowMergeConflicts`) VALUES ('%s', %d)", error,
1826  table, numconflicts);
1827  if (r != ERROR_SUCCESS)
1828  return r;
1829 
1830  r = MSI_ViewExecute(view, NULL);
1831  msiobj_release(&view->hdr);
1832  return r;
1833 }
1834 
1835 UINT WINAPI MsiDatabaseMergeW( MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge, const WCHAR *szTableName )
1836 {
1837  struct list tabledata = LIST_INIT(tabledata);
1838  struct list *item, *cursor;
1839  MSIDATABASE *db, *merge;
1840  MERGETABLE *table;
1841  BOOL conflicts;
1842  UINT r;
1843 
1844  TRACE( "%lu, %lu, %s\n", hDatabase, hDatabaseMerge, debugstr_w(szTableName) );
1845 
1846  if (szTableName && !*szTableName)
1847  return ERROR_INVALID_TABLE;
1848 
1849  db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
1850  merge = msihandle2msiinfo(hDatabaseMerge, MSIHANDLETYPE_DATABASE);
1851  if (!db || !merge)
1852  {
1854  goto done;
1855  }
1856 
1857  r = gather_merge_data(db, merge, &tabledata);
1858  if (r != ERROR_SUCCESS)
1859  goto done;
1860 
1861  conflicts = FALSE;
1862  LIST_FOR_EACH_ENTRY(table, &tabledata, MERGETABLE, entry)
1863  {
1864  if (table->numconflicts)
1865  {
1866  conflicts = TRUE;
1867 
1868  r = update_merge_errors(db, szTableName, table->name,
1869  table->numconflicts);
1870  if (r != ERROR_SUCCESS)
1871  break;
1872  }
1873  else
1874  {
1875  r = merge_table(db, table);
1876  if (r != ERROR_SUCCESS)
1877  break;
1878  }
1879  }
1880 
1881  LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
1882  {
1884  list_remove(&table->entry);
1886  }
1887 
1888  if (conflicts)
1890 
1891 done:
1892  msiobj_release(&db->hdr);
1893  msiobj_release(&merge->hdr);
1894  return r;
1895 }
1896 
1898 {
1900  MSIDATABASE *db;
1901 
1902  TRACE( "%lu\n", handle );
1903 
1905  return MSIDBSTATE_ERROR;
1906 
1907  if (db->mode != MSI_OPEN_READONLY )
1909  msiobj_release( &db->hdr );
1910 
1911  return ret;
1912 }
1913 
1915 {
1917 }
1918 
1920 {
1921  MSIHANDLE handle;
1923  *rec = NULL;
1924  if (!r)
1925  *rec = marshal_record(handle);
1927  return r;
1928 }
1929 
1931 {
1932  return MsiGetSummaryInformationW(db, NULL, updatecount, suminfo);
1933 }
1934 
1936 {
1937  return MsiDatabaseOpenViewW(db, query, view);
1938 }
void msiobj_addref(MSIOBJECTHDR *info)
Definition: handle.c:217
LPWSTR tempfolder
Definition: msipriv.h:114
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
BOOL WINAPI CreateDirectoryW(IN LPCWSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:90
MERGETABLE * curtable
Definition: database.c:1234
struct wire_record * marshal_record(MSIHANDLE handle) DECLSPEC_HIDDEN
Definition: record.c:1109
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
MSISTREAM * streams
Definition: msipriv.h:120
MSIRECORD * MSI_CloneRecord(MSIRECORD *) DECLSPEC_HIDDEN
Definition: record.c:921
static LPWSTR msi_build_createsql_postlude(LPWSTR *primary_keys, DWORD num_keys)
Definition: database.c:550
#define LIST_FOR_EACH_SAFE(cursor, cursor2, list)
Definition: list.h:192
struct list * tabledata
Definition: database.c:1236
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:597
#define CloseHandle
Definition: compat.h:598
static HRESULT db_initialize(IStorage *stg, const GUID *clsid)
Definition: database.c:104
static PDB pdb
Definition: db.cpp:172
Definition: fci.c:115
MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(MSIHANDLE hDatabase, const WCHAR *szTableName)
Definition: msiquery.c:1167
UINT MSI_ViewGetColumnInfo(MSIQUERY *, MSICOLINFO, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:603
#define ERROR_SUCCESS
Definition: deptool.c:10
struct _tagMERGEDATA MERGEDATA
static UINT merge_table(MSIDATABASE *db, MERGETABLE *table)
Definition: database.c:1776
const WCHAR * name
static UINT msi_export_summaryinformation(MSIDATABASE *db, HANDLE handle)
Definition: database.c:1033
HRESULT hr
Definition: shlfolder.c:183
#define error(str)
Definition: mkdosfs.c:1605
#define __cdecl
Definition: accygwin.h:79
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
UINT TABLE_CreateView(MSIDATABASE *db, LPCWSTR name, MSIVIEW **view) DECLSPEC_HIDDEN
Definition: table.c:2189
UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
Definition: database.c:317
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID
Definition: msipriv.h:84
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
UINT WINAPI MsiDatabaseExportA(MSIHANDLE handle, const char *szTable, const char *szFolder, const char *szFilename)
Definition: database.c:1158
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:923
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static UINT msi_export_forcecodepage(HANDLE handle, UINT codepage)
Definition: database.c:1021
UINT MSI_ViewModify(MSIQUERY *, MSIMODIFY, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:698
#define TRUE
Definition: types.h:120
GLsizei const GLchar ** path
Definition: glext.h:7234
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
MSIOBJECTHDR hdr
Definition: msipriv.h:151
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define CP_ACP
Definition: compat.h:109
UINT __cdecl s_remote_DatabaseGetPrimaryKeys(MSIHANDLE db, LPCWSTR table, struct wire_record **rec)
Definition: database.c:1919
GLuint GLuint GLsizei count
Definition: gl.h:1545
UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
Definition: database.c:140
static UINT merge_diff_row(MSIRECORD *rec, LPVOID param)
Definition: database.c:1467
UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec)
Definition: msiquery.c:1080
#define WARN(fmt,...)
Definition: debug.h:112
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
UINT MSI_RecordGetStringW(MSIRECORD *, UINT, LPWSTR, LPDWORD) DECLSPEC_HIDDEN
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:502
#define STGM_CREATE
Definition: objbase.h:926
BOOL MSI_RecordsAreEqual(MSIRECORD *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: record.c:986
static UINT msi_get_table_labels(MSIDATABASE *db, LPCWSTR table, LPWSTR **labels, DWORD *numlabels)
Definition: database.c:1527
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:615
GLsizei GLenum GLenum * types
Definition: glext.h:7753
const char * fmt
Definition: wsprintf.c:30
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
#define ERROR_DATATYPE_MISMATCH
Definition: winerror.h:987
const struct column * columns
GLdouble GLdouble t
Definition: gl.h:2047
int MSICONDITION
Definition: winemsi.idl:29
struct list rows
Definition: database.c:1213
UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase, const WCHAR *szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
Definition: suminfo.c:514
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
UINT write_stream_data(IStorage *stg, LPCWSTR stname, LPCVOID data, UINT sz, BOOL bTable) DECLSPEC_HIDDEN
Definition: table.c:296
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
static LPWSTR create_diff_row_query(MSIDATABASE *merge, MSIQUERY *view, LPWSTR table, MSIRECORD *rec)
Definition: database.c:1412
void enum_stream_names(IStorage *stg) DECLSPEC_HIDDEN
Definition: table.c:204
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:5644
GLuint buffer
Definition: glext.h:5915
const WCHAR * table
Definition: database.c:981
static void msi_free(void *mem)
Definition: msipriv.h:1159
static UINT msi_export_field(HANDLE handle, MSIRECORD *row, UINT field)
Definition: database.c:883
string_table * msi_load_string_table(IStorage *stg, UINT *bytes_per_strref) DECLSPEC_HIDDEN
Definition: string.c:478
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define cmp(status, error)
Definition: error.c:114
#define MSIHANDLETYPE_DATABASE
Definition: msipriv.h:722
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
Definition: msipriv.h:83
#define MSI_OPEN_CREATEDIRECT
Definition: msipriv.h:103
char * LPSTR
Definition: xmlstorage.h:182
const char * filename
Definition: ioapi.h:135
static UINT update_merge_errors(MSIDATABASE *db, LPCWSTR error, LPWSTR table, DWORD numconflicts)
Definition: database.c:1806
#define IS_INTMSIDBOPEN(x)
Definition: database.c:53
#define lstrlenW
Definition: compat.h:609
static BOOL merge_type_match(LPCWSTR type1, LPCWSTR type2)
Definition: database.c:1239
static void * msi_realloc(void *mem, size_t len) __WINE_ALLOC_SIZE(2)
Definition: msipriv.h:1154
LPWSTR * columns
Definition: database.c:1216
#define FILE_SHARE_READ
Definition: compat.h:136
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1148
UINT MSI_RecordGetStringA(MSIRECORD *, UINT, LPSTR, LPDWORD) DECLSPEC_HIDDEN
Definition: record.c:351
UINT MSI_DatabaseGetPrimaryKeys(MSIDATABASE *, LPCWSTR, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:1044
UINT WINAPIV MSI_OpenQuery(MSIDATABASE *, MSIQUERY **, LPCWSTR,...) DECLSPEC_HIDDEN
Definition: msiquery.c:138
__WINE_SERVER_LIST_INLINE struct list * list_head(const struct list *list)
Definition: list.h:131
static const CHAR suminfo[]
Definition: db.c:2206
BOOL TABLE_Exists(MSIDATABASE *db, LPCWSTR name) DECLSPEC_HIDDEN
Definition: table.c:960
#define sprintf(buf, format,...)
Definition: sprintf.c:55
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
#define MSI_OPEN_DIRECT
Definition: msipriv.h:101
void * alloc_msiobject(UINT type, UINT size, msihandledestructor destroy)
Definition: handle.c:201
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
MSIDATABASE * merge
Definition: database.c:1233
#define ERROR_WRITE_FAULT
Definition: winerror.h:132
HANDLE handle
Definition: database.c:979
#define L(x)
Definition: ntvdm.h:50
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:280
VOID msi_destroy_stringtable(string_table *st) DECLSPEC_HIDDEN
Definition: string.c:107
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:377
LPWSTR path
Definition: msipriv.h:112
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
string_table * strings
Definition: msipriv.h:110
UINT MSI_RecordSetStreamFromFileW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:683
_STLP_MOVE_TO_STD_NAMESPACE _OutputIter merge(_InputIter1 __first1, _InputIter1 __last1, _InputIter2 __first2, _InputIter2 __last2, _OutputIter __result)
Definition: _algo.c:1419
if SUCCEEDED(hr)
#define GENERIC_WRITE
Definition: nt_native.h:90
unsigned long MSIHANDLE
Definition: winemsi.idl:24
#define debugstr_w
Definition: kernel32.h:32
static void free_transforms(MSIDATABASE *db)
Definition: database.c:55
static UINT merge_verify_primary_keys(MSIDATABASE *db, MSIDATABASE *mergedb, LPCWSTR table)
Definition: database.c:1317
#define FIXME(fmt,...)
Definition: debug.h:111
struct list entry
static PVOID ptr
Definition: dispmode.c:27
#define MSI_OPEN_READONLY
Definition: msipriv.h:99
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
int codepage
Definition: win_iconv.c:156
const WCHAR * str
static UINT msi_export_row(MSIRECORD *row, void *arg)
Definition: database.c:1016
struct list tables
Definition: msipriv.h:118
Definition: parser.c:48
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:433
const char * LPCSTR
Definition: xmlstorage.h:183
UINT WINAPI MsiDatabaseMergeA(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge, const char *szTableName)
Definition: database.c:1196
struct CFFOLDER folder
Definition: fdi.c:102
#define debugstr_guid
Definition: kernel32.h:35
static UINT msi_export_record(struct row_export_info *row_export_info, MSIRECORD *row, UINT start)
Definition: database.c:984
static LPWSTR msi_read_text_archive(LPCWSTR path, DWORD *len)
Definition: database.c:350
UINT WINAPI MsiDatabaseMergeW(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge, const WCHAR *szTableName)
Definition: database.c:1835
IStream * stream
Definition: msipriv.h:89
#define OPEN_EXISTING
Definition: compat.h:634
static UINT construct_record(DWORD num_columns, LPWSTR *types, LPWSTR *data, LPWSTR path, MSIRECORD **rec)
Definition: database.c:646
void free_cached_tables(MSIDATABASE *db) DECLSPEC_HIDDEN
Definition: table.c:470
MSIDBSTATE WINAPI MsiGetDatabaseState(MSIHANDLE handle)
Definition: database.c:1897
GLuint GLfloat * val
Definition: glext.h:7180
UINT MSI_ViewClose(MSIQUERY *) DECLSPEC_HIDDEN
Definition: msiquery.c:454
void append_storage_to_db(MSIDATABASE *db, IStorage *stg)
Definition: database.c:76
UINT __cdecl s_remote_DatabaseGetSummaryInformation(MSIHANDLE db, UINT updatecount, MSIHANDLE *suminfo)
Definition: database.c:1930
static VOID MSI_CloseDatabase(MSIOBJECTHDR *arg)
Definition: database.c:86
#define STGM_READ
Definition: objbase.h:917
DWORD numlabels
Definition: database.c:1221
struct list entry
Definition: database.c:1212
UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, const WCHAR *szFolder, const WCHAR *szFilename)
Definition: database.c:838
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
static UINT MSI_DatabaseExport(MSIDATABASE *db, LPCWSTR table, LPCWSTR folder, LPCWSTR file)
Definition: database.c:1046
static UINT merge_diff_tables(MSIRECORD *rec, LPVOID param)
Definition: database.c:1706
UINT __cdecl s_remote_DatabaseOpenView(MSIHANDLE db, LPCWSTR query, MSIHANDLE *view)
Definition: database.c:1935
#define TRACE(s)
Definition: solgame.cpp:4
UINT bytes_per_strref
Definition: msipriv.h:111
GLsizeiptr size
Definition: glext.h:5919
MSICONDITION __cdecl s_remote_DatabaseIsTablePersistent(MSIHANDLE db, LPCWSTR table)
Definition: database.c:1914
#define MAX_STREAM_NAME_LEN
Definition: msipriv.h:56
Definition: id3.c:95
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
struct _tagMERGEROW MERGEROW
Definition: cmds.c:130
#define LIST_INIT(head)
Definition: queue.h:197
__wchar_t WCHAR
Definition: xmlstorage.h:180
Definition: parser.c:43
const WCHAR * folder
Definition: database.c:980
static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
Definition: database.c:733
#define debugstr_a
Definition: kernel32.h:31
const MSIVIEWOPS * ops
Definition: msipriv.h:355
LONG HRESULT
Definition: typedefs.h:79
BOOL WINAPI CopyFileW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN BOOL bFailIfExists)
Definition: copy.c:439
DWORD numcolumns
Definition: database.c:1217
HRESULT WINAPI StgOpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8755
static UINT msi_export_stream(const WCHAR *folder, const WCHAR *table, MSIRECORD *row, UINT field, UINT start)
Definition: database.c:926
static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns)
Definition: database.c:463
#define STGM_DIRECT
Definition: objbase.h:914
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
const char file[]
Definition: icontest.c:11
static LPWSTR msi_build_createsql_prelude(LPWSTR table)
Definition: database.c:449
DWORD numconflicts
Definition: database.c:1215
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIQUERY * curview
Definition: database.c:1235
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
static UINT msi_get_query_types(MSIQUERY *query, LPWSTR **types, DWORD *numtypes)
Definition: database.c:1585
MSIOBJECTHDR hdr
Definition: msipriv.h:129
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
static LPWSTR get_key_value(MSIQUERY *view, LPCWSTR key, MSIRECORD *rec)
Definition: database.c:1354
DWORD numtypes
Definition: database.c:1219
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
struct _tagMERGETABLE MERGETABLE
static UINT msi_get_query_columns(MSIQUERY *query, LPWSTR **columns, DWORD *numcolumns)
Definition: database.c:1556
GLuint GLuint end
Definition: gl.h:1545
LPWSTR * types
Definition: database.c:1218
HRESULT msi_init_string_table(IStorage *stg) DECLSPEC_HIDDEN
Definition: string.c:460
int ret
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:76
MSIDATABASE * db
Definition: database.c:1232
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
REFCLSID clsid
Definition: msctf.c:82
enum tagMSIDBSTATE MSIDBSTATE
const char * fullname
Definition: shader.c:1766
Definition: parse.h:22
static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
Definition: database.c:582
HKEY key
Definition: reg.c:28
Definition: stat.h:55
uint32_t entry
Definition: isohybrid.c:63
GLenum GLsizei len
Definition: glext.h:6722
HRESULT WINAPI StgCreateDocfile(LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8636
Definition: _list.h:228
#define GENERIC_READ
Definition: compat.h:135
static UINT msi_get_merge_table(MSIDATABASE *db, LPCWSTR name, MERGETABLE **ptable)
Definition: database.c:1661
#define err(...)
#define wcsrchr
Definition: compat.h:16
IN PCTCH line
Definition: pager.h:36
UINT msi_add_suminfo(MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns) DECLSPEC_HIDDEN
Definition: suminfo.c:1073
int _cdecl swprintf(const WCHAR *,...)
uint32_t DWORD_PTR
Definition: typedefs.h:65
GLenum mode
Definition: glext.h:6217
#define STGM_READWRITE
Definition: objbase.h:919
#define ERROR_MORE_DATA
Definition: dderror.h:13
LPWSTR * labels
Definition: database.c:1220
UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
Definition: handle.c:269
#define ERR(fmt,...)
Definition: debug.h:110
#define ERROR_INVALID_TABLE
Definition: winerror.h:986
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
UINT(* delete)(struct tagMSIVIEW *)
Definition: msipriv.h:324
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
UINT msi_set_string_table_codepage(string_table *st, UINT codepage) DECLSPEC_HIDDEN
Definition: string.c:676
#define S_OK
Definition: intsafe.h:52
#define CREATE_ALWAYS
Definition: disk.h:72
MSIRECORD * data
Definition: database.c:1227
static ATOM item
Definition: dde.c:856
const char cursor[]
Definition: icontest.c:13
#define lstrcpyW
Definition: compat.h:608
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ERROR_OPEN_FAILED
Definition: winerror.h:184
GLuint start
Definition: gl.h:1545
#define ARRAY_SIZE(a)
Definition: main.h:24
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1002
static void free_merge_table(MERGETABLE *table)
Definition: database.c:1627
static UINT gather_merge_data(MSIDATABASE *db, MSIDATABASE *merge, struct list *tabledata)
Definition: database.c:1757
#define MSI_OPEN_CREATE
Definition: msipriv.h:102
LPWSTR deletefile
Definition: msipriv.h:113
UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
Definition: database.c:298
MSIHANDLE alloc_msihandle(MSIOBJECTHDR *obj)
Definition: handle.c:111
#define ReadFile(a, b, c, d, e)
Definition: compat.h:601
#define MSI_OPEN_TRANSACT
Definition: msipriv.h:100
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4112
#define MultiByteToWideChar
Definition: compat.h:110
#define CreateFileW
Definition: compat.h:600
UINT MSI_RecordReadStream(MSIRECORD *, UINT, char *, LPDWORD) DECLSPEC_HIDDEN
Definition: record.c:761
UINT media_transform_disk_id
Definition: msipriv.h:117
UINT WINAPI MsiDatabaseExportW(MSIHANDLE handle, const WCHAR *szTable, const WCHAR *szFolder, const WCHAR *szFilename)
Definition: database.c:1143
static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, LPWSTR **records, int num_columns, int num_records, LPWSTR path)
Definition: database.c:690
struct list entry
Definition: database.c:1226
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, LPCWSTR szQuery, MSIHANDLE *phView)
Definition: msiquery.c:236
Definition: name.c:38
UINT msi_export_suminfo(MSIDATABASE *db, HANDLE handle) DECLSPEC_HIDDEN
Definition: suminfo.c:1190
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1142
UINT num_streams
Definition: msipriv.h:121
static IOleDocumentView * view
Definition: activex.c:1749
#define STGM_TRANSACTED
Definition: objbase.h:915
UINT WINAPI MsiDatabaseImportA(MSIHANDLE handle, const char *szFolder, const char *szFilename)
Definition: database.c:853
IStorage * storage
Definition: msipriv.h:109
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define STGM_SHARE_DENY_WRITE
Definition: objbase.h:922
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define LIST_ENTRY(type)
Definition: queue.h:175
void * msihandle2msiinfo(MSIHANDLE handle, UINT type)
Definition: handle.c:158
static void free_streams(MSIDATABASE *db)
Definition: database.c:66
UINT MSI_IterateRecords(MSIQUERY *, LPDWORD, record_func, LPVOID) DECLSPEC_HIDDEN
Definition: msiquery.c:163
#define TRACE_ON(x)
Definition: compat.h:75
static LPWSTR msi_import_stream_filename(LPCWSTR path, LPCWSTR name)
Definition: database.c:622
#define LOWORD(l)
Definition: pedump.c:82
GLenum query
Definition: glext.h:7781
Definition: dsound.c:943
MSIOBJECTHDR hdr
Definition: msipriv.h:108
WINE_DEFAULT_DEBUG_CHANNEL(msi)
static WCHAR * strdupAtoW(const char *str)
Definition: main.c:65
static void merge_free_rows(MERGETABLE *table)
Definition: database.c:1613
#define MSI_OPEN_PATCHFILE
Definition: msipriv.h:104
UINT media_transform_offset
Definition: msipriv.h:116
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
UINT msi_get_string_table_codepage(const string_table *st) DECLSPEC_HIDDEN
Definition: string.c:671
struct list transforms
Definition: msipriv.h:119
UINT MSI_RecordGetFieldCount(const MSIRECORD *rec) DECLSPEC_HIDDEN
Definition: record.c:108
static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries, DWORD *len)
Definition: database.c:380
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
Definition: database.c:1252
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
Definition: copy.c:22
static struct @1508 save_path[MOVE_LIST_SIZE]
UINT(* insert_row)(struct tagMSIVIEW *view, MSIRECORD *record, UINT row, BOOL temporary)
Definition: msipriv.h:283
Definition: fci.c:126
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN
GLuint const GLchar * name
Definition: glext.h:6031