summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-01-17 03:32:23 +0100
committerMarc-André Lureau <marcandre.lureau@gmail.com>2013-01-17 03:32:23 +0100
commitceb4e1d3de8304c233b5294e2161fca1b7a3785e (patch)
treee155cf73ba9932cc23ccffaaa606f2f44c6971dc /tools
parente5ceb0c21bf680088a17321f18a00eea439cff54 (diff)
downloadmsitools-ceb4e1d3de8304c233b5294e2161fca1b7a3785e.tar.gz
msitools-ceb4e1d3de8304c233b5294e2161fca1b7a3785e.tar.xz
msitools-ceb4e1d3de8304c233b5294e2161fca1b7a3785e.zip
Start a msiextract tool
Diffstat (limited to 'tools')
-rw-r--r--tools/msiextract.vala146
1 files changed, 146 insertions, 0 deletions
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<string, string> 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<string, Libmsi.Record> (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<string, string> (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<string, string> (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;
+}