From f2890dc1d0f8cd5d6e36f8e4c5896edbeebe586d Mon Sep 17 00:00:00 2001 From: David Hicks Date: Sun, 29 Jun 2014 01:26:50 +1000 Subject: [PATCH] Add hexadecimal binary output conversion option This commit adds another binary output conversion option to convert binary blobs into hexadecimal notation, similar to the output of the following command: xxd -p binaryfile.bin | tr -d '\n' (In other words, a single line string of hexadecimal characters representing a binary blob) When exporting SQL INSERT statements for SQLite and PostgreSQL and when the hexadecimal notation is specified with 'mdb-export -b hex ...', special consideration is given to ensure that binary blobs are safely written to the SQLite or PostgreSQL database. Signed-off-by: David Hicks --- doc/mdb-export.txt | 20 ++++++++++---------- include/mdbtools.h | 3 ++- src/gmdb2/table_export.c | 12 ++++++++++-- src/util/mdb-export.c | 32 +++++++++++++++++++++++++++----- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/doc/mdb-export.txt b/doc/mdb-export.txt index 6a428e3..98adf71 100644 --- a/doc/mdb-export.txt +++ b/doc/mdb-export.txt @@ -10,16 +10,16 @@ DESCRIPTION It produces a CSV (comma separated value) output for the given table. Such output is suitable for importation into databases or spreadsheets. OPTIONS - -H Suppress header row - -Q Don't wrap text-like fields (text, memo, date) in quotes. If not specified text fiels will be surrounded by " (double quote) characters. - -d Specify an alternative column delimiter If no delimiter is specified, table names will be delimited by a , (comma) character. - -R Specify a row delimiter - -I backend INSERT statements (instead of CSV). You must specify which SQL backend dialect to use. Allowed values are: access, sybase, oracle, postgres, mysql and sqlite. - -D Set the date format (see strftime(3) for details) - -q Use to wrap text-like fields. Default is ". - -X Use to escape quoted characters within a field. Default is doubling. - -N namespace Prefix identifiers with namespace. - -b strip|raw|octal Binary export mode: strip binaries, export as-is, or output \ooo style octal data. + -H Suppress header row + -Q Don't wrap text-like fields (text, memo, date) in quotes. If not specified text fiels will be surrounded by " (double quote) characters. + -d Specify an alternative column delimiter If no delimiter is specified, table names will be delimited by a , (comma) character. + -R Specify a row delimiter + -I backend INSERT statements (instead of CSV). You must specify which SQL backend dialect to use. Allowed values are: access, sybase, oracle, postgres, mysql and sqlite. + -D Set the date format (see strftime(3) for details) + -q Use to wrap text-like fields. Default is ". + -X Use to escape quoted characters within a field. Default is doubling. + -N namespace Prefix identifiers with namespace. + -b strip|raw|octal|hex Binary export mode: strip binaries, export as-is, output \ooo style octal data or output \xx style hexadecimal data. NOTES diff --git a/include/mdbtools.h b/include/mdbtools.h index 60ed640..2d71b03 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -180,7 +180,8 @@ enum { enum { MDB_BINEXPORT_STRIP, MDB_BINEXPORT_RAW, - MDB_BINEXPORT_OCTAL + MDB_BINEXPORT_OCTAL, + MDB_BINEXPORT_HEXADECIMAL }; #define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) /* obsolete */ diff --git a/src/gmdb2/table_export.c b/src/gmdb2/table_export.c index afb4f2e..0c9af84 100644 --- a/src/gmdb2/table_export.c +++ b/src/gmdb2/table_export.c @@ -47,6 +47,7 @@ MdbCatalogEntry *cat_entry; #define BIN_STRIP "Strip" #define BIN_RAW "Raw" #define BIN_OCTAL "Octal" +#define BIN_HEXADECIMAL "Hexademical" void gmdb_export_get_delimiter(GladeXML *xml, gchar *delimiter, int max_buf) @@ -134,6 +135,8 @@ gmdb_export_get_binmode(GladeXML *xml) return MDB_BINEXPORT_STRIP; else if (!strcmp(str,BIN_OCTAL)) return MDB_BINEXPORT_OCTAL; + else if (!strcmp(str,BIN_HEXADECIMAL)) + return MDB_BINEXPORT_HEXADECIMAL; else return MDB_BINEXPORT_RAW; } @@ -200,16 +203,20 @@ gmdb_print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int if (!*col_val) break; - if (quote_len && !strncmp(col_val, quote_char, quote_len)) { + int is_binary_hex_col = is_binary_type(col_type) && bin_mode == MDB_BINEXPORT_HEXADECIMAL; + + if (quote_len && !strncmp(col_val, quote_char, quote_len) && !is_binary_hex_col) { fprintf(outfile, "%s%s", escape_char, quote_char); col_val += quote_len; #ifndef DONT_ESCAPE_ESCAPE - } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len)) { + } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len) && !is_binary_hex_col) { fprintf(outfile, "%s%s", escape_char, escape_char); col_val += orig_escape_len; #endif } else if (is_binary_type(col_type) && *col_val <= 0 && bin_mode == MDB_BINEXPORT_OCTAL) fprintf(outfile, "\\%03o", *(unsigned char*)col_val++); + } else if (is_binary_hex_col) + fprintf(outfilt, "%02X", *(unsigned char*)col_val++); else putc(*col_val++, outfile); } @@ -366,5 +373,6 @@ gmdb_table_export_populate_dialog(GladeXML *xml) gtk_combo_box_append_text(combobox, BIN_STRIP); gtk_combo_box_append_text(combobox, BIN_RAW); gtk_combo_box_append_text(combobox, BIN_OCTAL); + gtk_combo_box_append_text(combobox, BIN_HEXADECIMAL); gtk_combo_box_set_active(combobox, 1); } diff --git a/src/util/mdb-export.c b/src/util/mdb-export.c index f91b180..72670f2 100644 --- a/src/util/mdb-export.c +++ b/src/util/mdb-export.c @@ -56,17 +56,21 @@ print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_l if (!*col_val) break; - if (quote_len && !strncmp(col_val, quote_char, quote_len)) { + int is_binary_hex_col = is_binary_type(col_type) && bin_mode == MDB_BINEXPORT_HEXADECIMAL; + + if (quote_len && !strncmp(col_val, quote_char, quote_len) && !is_binary_hex_col) { fprintf(outfile, "%s%s", escape_char, quote_char); col_val += quote_len; #ifndef DONT_ESCAPE_ESCAPE - } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len)) { + } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len) && !is_binary_hex_col) { fprintf(outfile, "%s%s", escape_char, escape_char); col_val += orig_escape_len; #endif - } else if (is_binary_type(col_type) && *col_val <= 0 && bin_mode == MDB_BINEXPORT_OCTAL) + } else if (is_binary_type(col_type) && *col_val <= 0 && bin_mode == MDB_BINEXPORT_OCTAL) { fprintf(outfile, "\\%03o", *(unsigned char*)col_val++); - else + } else if (is_binary_hex_col) { + fprintf(outfile, "%02X", *(unsigned char*)col_val++); + } else putc(*col_val++, outfile); } fputs(quote_char, outfile); @@ -133,6 +137,8 @@ main(int argc, char **argv) bin_mode = MDB_BINEXPORT_RAW; else if (!strcmp(optarg, "octal")) bin_mode = MDB_BINEXPORT_OCTAL; + else if (!strcmp(optarg, "hex")) + bin_mode = MDB_BINEXPORT_HEXADECIMAL; else { fprintf(stderr, "Invalid binary mode\n"); exit(1); @@ -255,7 +261,23 @@ main(int argc, char **argv) value = bound_values[i]; length = bound_lens[i]; } - print_col(outfile, value, quote_text, col->col_type, length, quote_char, escape_char, bin_mode); + /* Correctly handle insertion of binary blobs into SQLite using the string literal notation of X'1234ABCD...' */ + if (!strcmp(mdb->backend_name, "sqlite") && is_binary_type(col->col_type) && bin_mode == MDB_BINEXPORT_HEXADECIMAL) { + char *quote_char_binary_sqlite = (char *) g_strdup("'"); + fputs("X", outfile); + print_col(outfile, value, quote_text, col->col_type, length, quote_char_binary_sqlite, escape_char, bin_mode); + g_free (quote_char_binary_sqlite); + /* Correctly handle insertion of binary blobs into PostgreSQL using the notation of decode('1234ABCD...', 'hex') */ + } else if (!strcmp(mdb->backend_name, "postgres") && is_binary_type(col->col_type) && bin_mode == MDB_BINEXPORT_HEXADECIMAL) { + char *quote_char_binary_postgres = (char *) g_strdup("'"); + fputs("decode(", outfile); + print_col(outfile, value, quote_text, col->col_type, length, quote_char_binary_postgres, escape_char, bin_mode); + fputs(", 'hex')", outfile); + g_free (quote_char_binary_postgres); + /* No special treatment for other backends or when hexadecimal notation hasn't been selected with the -b hex command line option */ + } else { + print_col(outfile, value, quote_text, col->col_type, length, quote_char, escape_char, bin_mode); + } if (col->col_type == MDB_OLE) free(value); }