Hans Leidekker : programs: Add winemsibuilder.
Alexandre Julliard
julliard at winehq.org
Tue Feb 1 12:25:00 CST 2011
Module: wine
Branch: master
Commit: 13700720573bdbadb3bbeb25f1e8a88c11dbf605
URL: http://source.winehq.org/git/wine.git/?a=commit;h=13700720573bdbadb3bbeb25f1e8a88c11dbf605
Author: Hans Leidekker <hans at codeweavers.com>
Date: Tue Feb 1 14:01:42 2011 +0100
programs: Add winemsibuilder.
---
configure | 1 +
configure.ac | 1 +
programs/winemsibuilder/Makefile.in | 8 +
programs/winemsibuilder/main.c | 281 +++++++++++++++++++++++++++++++++++
4 files changed, 291 insertions(+), 0 deletions(-)
diff --git a/configure b/configure
index 89cbede..64a7c50 100755
--- a/configure
+++ b/configure
@@ -15427,6 +15427,7 @@ wine_fn_config_program winedevice enable_winedevice install
wine_fn_config_program winefile enable_winefile po,install,installbin
wine_fn_config_program winemenubuilder enable_winemenubuilder install
wine_fn_config_program winemine enable_winemine po,install,installbin
+wine_fn_config_program winemsibuilder enable_winemsibuilder install
wine_fn_config_program winepath enable_winepath install,installbin
wine_fn_config_program winetest enable_winetest
wine_fn_config_program winevdm enable_win16 install
diff --git a/configure.ac b/configure.ac
index 48ed667..6d8b574 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2928,6 +2928,7 @@ WINE_CONFIG_PROGRAM(winedevice,,[install])
WINE_CONFIG_PROGRAM(winefile,,[po,install,installbin])
WINE_CONFIG_PROGRAM(winemenubuilder,,[install])
WINE_CONFIG_PROGRAM(winemine,,[po,install,installbin])
+WINE_CONFIG_PROGRAM(winemsibuilder,,[install])
WINE_CONFIG_PROGRAM(winepath,,[install,installbin])
WINE_CONFIG_PROGRAM(winetest)
WINE_CONFIG_PROGRAM(winevdm,enable_win16,[install])
diff --git a/programs/winemsibuilder/Makefile.in b/programs/winemsibuilder/Makefile.in
new file mode 100644
index 0000000..14517f1
--- /dev/null
+++ b/programs/winemsibuilder/Makefile.in
@@ -0,0 +1,8 @@
+MODULE = winemsibuilder.exe
+APPMODE = -mconsole -municode
+IMPORTS = msi ole32
+EXTRADEFS = -DWINE_NO_UNICODE_MACROS
+
+C_SRCS = main.c
+
+ at MAKE_PROG_RULES@
diff --git a/programs/winemsibuilder/main.c b/programs/winemsibuilder/main.c
new file mode 100644
index 0000000..ea4607e
--- /dev/null
+++ b/programs/winemsibuilder/main.c
@@ -0,0 +1,281 @@
+/*
+ * winemsibuilder - tool to build MSI packages
+ *
+ * Copyright 2010 Hans Leidekker for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+
+#include <stdio.h>
+#include <windows.h>
+#include <msi.h>
+#include <msiquery.h>
+#include <objbase.h>
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winemsibuilder);
+
+static UINT open_database( const WCHAR *msifile, MSIHANDLE *handle )
+{
+ UINT r;
+ MSIHANDLE hdb;
+
+ if (GetFileAttributesW( msifile ) == INVALID_FILE_ATTRIBUTES)
+ {
+ r = MsiOpenDatabaseW( msifile, MSIDBOPEN_CREATE, &hdb );
+ if (r != ERROR_SUCCESS)
+ {
+ WINE_ERR( "failed to create package database %s (%u)\n", wine_dbgstr_w(msifile), r );
+ return r;
+ }
+ r = MsiDatabaseCommit( hdb );
+ if (r != ERROR_SUCCESS)
+ {
+ WINE_ERR( "failed to commit database (%u)\n", r );
+ MsiCloseHandle( hdb );
+ return r;
+ }
+ }
+ else
+ {
+ r = MsiOpenDatabaseW( msifile, MSIDBOPEN_TRANSACT, &hdb );
+ if (r != ERROR_SUCCESS)
+ {
+ WINE_ERR( "failed to open package database %s (%u)\n", wine_dbgstr_w(msifile), r );
+ return r;
+ }
+ }
+
+ *handle = hdb;
+ return ERROR_SUCCESS;
+}
+
+static int import_tables( const WCHAR *msifile, WCHAR **tables )
+{
+ UINT r;
+ MSIHANDLE hdb;
+ WCHAR *dir;
+ DWORD len;
+
+ r = open_database( msifile, &hdb );
+ if (r != ERROR_SUCCESS) return 1;
+
+ len = GetCurrentDirectoryW( 0, NULL );
+ if (!(dir = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
+ {
+ MsiCloseHandle( hdb );
+ return 1;
+ }
+ GetCurrentDirectoryW( len + 1, dir );
+
+ while (*tables)
+ {
+ r = MsiDatabaseImportW( hdb, dir, *tables );
+ if (r != ERROR_SUCCESS)
+ {
+ WINE_ERR( "failed to import table %s (%u)\n", wine_dbgstr_w(*tables), r );
+ break;
+ }
+ tables++;
+ }
+
+ if (r == ERROR_SUCCESS)
+ {
+ r = MsiDatabaseCommit( hdb );
+ if (r != ERROR_SUCCESS)
+ WINE_ERR( "failed to commit changes (%u)\n", r );
+ }
+
+ HeapFree( GetProcessHeap(), 0, dir );
+ MsiCloseHandle( hdb );
+ return (r != ERROR_SUCCESS);
+}
+
+/* taken from dlls/msi/table.c */
+static int utf2mime( int x )
+{
+ if (x >= '0' && x <= '9')
+ return x - '0';
+ if (x >= 'A' && x <= 'Z')
+ return x - 'A' + 10;
+ if (x >= 'a' && x <= 'z')
+ return x - 'a' + 10 + 26;
+ if (x == '.')
+ return 10 + 26 + 26;
+ if (x == '_')
+ return 10 + 26 + 26 + 1;
+ return -1;
+}
+
+#define MAX_STREAM_NAME 0x1f
+
+static WCHAR *encode_stream( const WCHAR *in )
+{
+ DWORD c, next, count;
+ WCHAR *out, *p;
+
+ count = strlenW( in );
+ if (count > MAX_STREAM_NAME)
+ return NULL;
+
+ count += 2;
+ if (!(out = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) ))) return NULL;
+ p = out;
+ while (count--)
+ {
+ c = *in++;
+ if (!c)
+ {
+ *p = c;
+ return out;
+ }
+ if (c < 0x80 && utf2mime( c ) >= 0)
+ {
+ c = utf2mime( c ) + 0x4800;
+ next = *in;
+ if (next && next < 0x80)
+ {
+ next = utf2mime( next );
+ if (next != -1)
+ {
+ next += 0x3ffffc0;
+ c += next << 6;
+ in++;
+ }
+ }
+ }
+ *p++ = c;
+ }
+ HeapFree( GetProcessHeap(), 0, out );
+ return NULL;
+}
+
+static int add_stream( const WCHAR *msifile, const WCHAR *stream, const WCHAR *file )
+{
+ UINT r;
+ HRESULT hr;
+ MSIHANDLE hdb;
+ IStorage *stg;
+ IStream *stm = NULL;
+ HANDLE handle;
+ char buffer[4096];
+ ULARGE_INTEGER size;
+ DWORD low, high, read;
+ WCHAR *encname;
+ int ret = 1;
+
+ /* make sure we have the right type of file */
+ r = open_database( msifile, &hdb );
+ if (r != ERROR_SUCCESS) return 1;
+ MsiCloseHandle( hdb );
+
+ hr = StgOpenStorage( msifile, NULL, STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
+ if (hr != S_OK)
+ {
+ WINE_WARN( "failed to open storage %s (0x%08x)\n", wine_dbgstr_w(msifile), hr );
+ return 1;
+ }
+ encname = encode_stream( stream );
+ if (!encname)
+ {
+ WINE_WARN( "failed to encode stream name %s\n", wine_dbgstr_w(stream) );
+ goto done;
+ }
+ hr = IStorage_CreateStream( stg, encname, STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
+ if (hr != S_OK)
+ {
+ WINE_WARN( "failed to create stream %s (0x%08x)\n", wine_dbgstr_w(encname), hr );
+ goto done;
+ }
+ handle = CreateFileW( file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ WINE_WARN( "failed to open file %s (%u)\n", wine_dbgstr_w(file), GetLastError() );
+ goto done;
+ }
+ low = GetFileSize( handle, &high );
+ if (low == INVALID_FILE_SIZE || high)
+ {
+ WINE_WARN( "file %s too big\n", wine_dbgstr_w(file) );
+ CloseHandle( handle );
+ goto done;
+ }
+ size.QuadPart = low;
+ hr = IStream_SetSize( stm, size );
+ if (hr != S_OK) goto done;
+
+ while (ReadFile( handle, buffer, sizeof(buffer), &read, NULL ) && read)
+ {
+ hr = IStream_Write( stm, buffer, read, NULL );
+ if (hr != S_OK) break;
+ size.QuadPart -= read;
+ }
+ CloseHandle( handle );
+ if (size.QuadPart)
+ {
+ WINE_WARN( "failed to write stream contents\n" );
+ goto done;
+ }
+ IStorage_Commit( stg, 0 );
+ ret = 0;
+
+done:
+ HeapFree( GetProcessHeap(), 0, encname );
+ if (stm) IStream_Release( stm );
+ IStorage_Release( stg );
+ return ret;
+}
+
+static void show_usage( void )
+{
+ WINE_MESSAGE(
+ "Usage: winemsibuilder [OPTION] [MSIFILE] ...\n"
+ "Options:\n"
+ " -i package.msi table1.idt [table2.idt ...] Import one or more tables into the database.\n"
+ " -a package.msi stream file Add 'stream' to storage with contents of 'file'.\n"
+ "\nExisting tables or streams will be overwritten. If package.msi does not exist a new file\n"
+ "will be created with an empty database.\n"
+ );
+}
+
+int wmain( int argc, WCHAR *argv[] )
+{
+ if (argc < 3 || argv[1][0] != '-')
+ {
+ show_usage();
+ return 1;
+ }
+
+ switch (argv[1][1])
+ {
+ case 'i':
+ if (argc < 4) break;
+ return import_tables( argv[2], argv + 3 );
+ case 'a':
+ if (argc < 5) break;
+ return add_stream( argv[2], argv[3], argv[4] );
+ default:
+ WINE_WARN( "unknown option\n" );
+ break;
+ }
+
+ show_usage();
+ return 1;
+}
More information about the wine-cvs
mailing list