From ceb4e1d3de8304c233b5294e2161fca1b7a3785e Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 17 Jan 2013 03:32:23 +0100 Subject: Start a msiextract tool --- tools/msiextract.vala | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 tools/msiextract.vala (limited to 'tools') diff --git a/tools/msiextract.vala b/tools/msiextract.vala new file mode 100644 index 0000000..ba9b21a --- /dev/null +++ b/tools/msiextract.vala @@ -0,0 +1,146 @@ +using Posix; + +static bool version; +static bool list_only; +[CCode (array_length = false, array_null_terminated = true)] +static string[] files; + +private const OptionEntry[] options = { + { "version", 0, 0, OptionArg.NONE, ref version, N_("Display version number"), null }, + { "list", 0, 0, OptionArg.NONE, ref list_only, N_("List files only"), null }, + { "", 0, 0, OptionArg.FILENAME_ARRAY, ref files, null, N_("MSI_FILE...") }, + { null } +}; + +public string get_long_name (string str) { + var names = str.split ("|", 2); + if (names.length == 2) + return names[1]; + + return str; +} + +public void extract_cab (Libmsi.Database db, string cab, + HashTable cab_to_name) throws GLib.Error +{ + if (cab.has_prefix ("#")) { + var name = cab.substring (1); + var query = new Libmsi.Query (db, "SELECT `Data` FROM `_Streams` WHERE `Name` = '%s'".printf (name)); + query.execute (null); + var rec = query.fetch (); + var cabinet = new GCab.Cabinet (); + cabinet.load (rec.get_stream (1)); + } +} + +public int main (string[] args) { + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); + Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + Intl.textdomain (Config.GETTEXT_PACKAGE); + GLib.Environment.set_application_name ("msiextract"); + + var parameter_string = _("- a msi files extracting tool"); + var opt_context = new OptionContext (parameter_string); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + + try { + opt_context.parse (ref args); + } catch (OptionError.BAD_VALUE err) { + GLib.stdout.printf (opt_context.get_help (true, null)); + return 1; + } catch (OptionError error) { + warning (error.message); + } + + if (version) { + GLib.stdout.printf ("%s\n", Config.PACKAGE_VERSION); + exit (0); + } + + if (files.length < 1) { + GLib.stderr.printf (_("Please specify input files.\n")); + exit (1); + } + + Libmsi.Database? db = null; + try { + db = new Libmsi.Database (files[0], null); + } catch (GLib.Error error) { + GLib.stderr.printf (error.message); + exit (1); + } + + var directories = new HashTable (str_hash, str_equal); + try { + var query = new Libmsi.Query (db, "SELECT * FROM `Directory`"); + query.execute (null); + do { + var rec = query.fetch (); + directories.insert (rec.get_string (1), rec); + } while (true); + } catch (GLib.Error error) { + } + + var components_dir = new HashTable (str_hash, str_equal); + try { + var query = new Libmsi.Query (db, "SELECT * FROM `Component`"); + query.execute (null); + do { + var rec = query.fetch (); + var dir_id = rec.get_string (3); + var dir_rec = directories.lookup (dir_id); + var dir = get_long_name (dir_rec.get_string (3)); + do { + var parent = dir_rec.get_string (2); + dir_rec = directories.lookup (parent); + if (dir_rec == null) + break; + parent = get_long_name (dir_rec.get_string (3)); + // only by intuition... + if (dir_rec.get_string (1) == "ProgramFilesFolder") + parent = "Program Files"; + else if (parent == ".") + continue; + else if (parent == "SourceDir") + break; + dir = Path.build_filename (parent, dir); + } while (true); + + components_dir.insert (rec.get_string (1), dir); + } while (true); + } catch (GLib.Error error) { + } + + var cab_to_name = new HashTable (str_hash, str_equal); + try { + var query = new Libmsi.Query (db, "SELECT * FROM `File`"); + query.execute (null); + do { + var rec = query.fetch (); + var dir = components_dir.lookup (rec.get_string (2)); + var file = Path.build_filename (dir, get_long_name (rec.get_string (3))); + if (list_only) + GLib.stdout.printf ("%s\n", file); + cab_to_name.insert (rec.get_string (1), file); + } while (true); + } catch (GLib.Error error) { + } + + if (list_only) + exit (0); + + message ("FIXME: gcab doesn't support extraction yet!"); + try { + var query = new Libmsi.Query (db, "SELECT * FROM `Media`"); + query.execute (null); + do { + var rec = query.fetch (); + var cab = rec.get_string (4); + extract_cab (db, cab, cab_to_name); + } while (true); + } catch (GLib.Error error) { + } + + return 0; +} -- cgit