From 7128a10cb4d1febc06bac49191c36fc1561141b0 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Tue, 15 Sep 2015 17:44:33 -0600
Subject: msidb: Add stub tool for manipulating MSI databases.

Signed-off-by: Erich E. Hoover <erich.e.hoover@wine-staging.com>
---
 configure.ac               |   1 +
 programs/msidb/Makefile.in |   8 +++
 programs/msidb/main.c      | 153 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+)
 create mode 100644 programs/msidb/Makefile.in
 create mode 100644 programs/msidb/main.c

diff --git a/configure.ac b/configure.ac
index bb879b0..06a0d24 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3514,6 +3514,7 @@ WINE_CONFIG_PROGRAM(ipconfig,,[install,po])
 WINE_CONFIG_PROGRAM(lodctr,,[install])
 WINE_CONFIG_PROGRAM(mofcomp,,[install])
 WINE_CONFIG_PROGRAM(mshta,,[install])
+WINE_CONFIG_PROGRAM(msidb,,[install,installbin])
 WINE_CONFIG_PROGRAM(msiexec,,[install,installbin,manpage])
 WINE_CONFIG_PROGRAM(net,,[install,po])
 WINE_CONFIG_PROGRAM(netsh,,[install])
diff --git a/programs/msidb/Makefile.in b/programs/msidb/Makefile.in
new file mode 100644
index 0000000..dae699c
--- /dev/null
+++ b/programs/msidb/Makefile.in
@@ -0,0 +1,8 @@
+MODULE    = msidb.exe
+APPMODE   = -mconsole -municode
+IMPORTS   = msi
+
+C_SRCS = \
+	main.c
+
+INSTALL_LIB = msidb.exe msidb
diff --git a/programs/msidb/main.c b/programs/msidb/main.c
new file mode 100644
index 0000000..43cc519
--- /dev/null
+++ b/programs/msidb/main.c
@@ -0,0 +1,153 @@
+/*
+ * msidb - command line tool for assembling MSI packages
+ *
+ * Copyright 2015 Erich E. Hoover
+ *
+ * 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
+
+#include <stdlib.h>
+#include <windows.h>
+#include <msi.h>
+#include <msiquery.h>
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
+
+struct msidb_state
+{
+    WCHAR *database_file;
+    WCHAR *table_folder;
+    MSIHANDLE database_handle;
+    BOOL create_database;
+};
+
+static void show_usage( void )
+{
+    WINE_MESSAGE(
+        "Usage: msidb [OPTION]...[OPTION]...\n"
+        "Options:\n"
+        "  -?                Show this usage message and exit.\n"
+        "  -c                Create database file (instead of opening existing file).\n"
+        "  -d package.msi    Path to the database file.\n"
+        "  -f folder         Folder in which to open/save the tables.\n"
+    );
+}
+
+static int valid_state( struct msidb_state *state )
+{
+    if (state->database_file == NULL)
+    {
+        FIXME( "GUI operation is not currently supported.\n" );
+        return 0;
+    }
+    if (state->table_folder == NULL)
+    {
+        ERR( "No table folder specified (-f option).\n" );
+        show_usage();
+        return 0;
+    }
+    return 1;
+}
+
+static int process_argument( struct msidb_state *state, int i, int argc, WCHAR *argv[] )
+{
+    /* msidb accepts either "-" or "/" style flags */
+    if (strlenW(argv[i]) != 2 || (argv[i][0] != '-' && argv[i][0] != '/'))
+    {
+        WINE_FIXME( "Table names are not currently supported.\n" );
+        show_usage();
+        exit( 1 );
+    }
+    switch( argv[i][1] )
+    {
+    case '?':
+        show_usage();
+        exit( 0 );
+    case 'c':
+        state->create_database = TRUE;
+        return 1;
+    case 'd':
+        if (i + 1 >= argc) return 0;
+        state->database_file = argv[i + 1];
+        return 2;
+    case 'f':
+        if (i + 1 >= argc) return 0;
+        state->table_folder = argv[i + 1];
+        return 2;
+    default:
+        break;
+    }
+    show_usage();
+    exit( 1 );
+}
+
+static int open_database( struct msidb_state *state )
+{
+    LPCWSTR db_mode = state->create_database ? MSIDBOPEN_CREATEDIRECT : MSIDBOPEN_DIRECT;
+    UINT ret;
+
+    ret = MsiOpenDatabaseW( state->database_file, db_mode, &state->database_handle );
+    if (ret != ERROR_SUCCESS)
+    {
+        ERR( "Failed to open database '%s', error %d\n", wine_dbgstr_w(state->database_file), ret );
+        return 0;
+    }
+    return 1;
+}
+
+static void close_database( struct msidb_state *state )
+{
+    UINT ret;
+
+    ret = MsiDatabaseCommit( state->database_handle );
+    if (ret != ERROR_SUCCESS)
+    {
+        ERR( "Failed to commit changes to database.\n" );
+        return;
+    }
+    ret = MsiCloseHandle( state->database_handle );
+    if (ret != ERROR_SUCCESS)
+    {
+        WARN( "Failed to close database handle.\n" );
+        return;
+    }
+}
+
+int wmain( int argc, WCHAR *argv[] )
+{
+    struct msidb_state state;
+    int i, n = 1;
+
+    memset( &state, 0x0, sizeof(state) );
+    /* process and validate all the command line flags */
+    for (i = 1; n && i < argc; i += n)
+        n = process_argument( &state, i, argc, argv );
+    if (!valid_state( &state ))
+        return 1;
+
+    /* perform the requested operations */
+    if (!open_database( &state ))
+    {
+        ERR( "Failed to open database '%s'.\n", wine_dbgstr_w(state.database_file) );
+        return 1;
+    }
+    close_database( &state );
+    return 0;
+}
-- 
2.6.1

