+ generate_header CStyle LGPLv2plus;
+
+ pr "\
+#include \"EXTERN.h\"
+#include \"perl.h\"
+#include \"XSUB.h\"
+
+#include <string.h>
+#include <hivex.h>
+
+#ifndef PRId64
+#define PRId64 \"lld\"
+#endif
+
+static SV *
+my_newSVll(long long val) {
+#ifdef USE_64_BIT_ALL
+ return newSViv(val);
+#else
+ char buf[100];
+ int len;
+ len = snprintf(buf, 100, \"%%\" PRId64, val);
+ return newSVpv(buf, len);
+#endif
+}
+
+#ifndef PRIu64
+#define PRIu64 \"llu\"
+#endif
+
+#if 0
+static SV *
+my_newSVull(unsigned long long val) {
+#ifdef USE_64_BIT_ALL
+ return newSVuv(val);
+#else
+ char buf[100];
+ int len;
+ len = snprintf(buf, 100, \"%%\" PRIu64, val);
+ return newSVpv(buf, len);
+#endif
+}
+#endif
+
+#if 0
+/* http://www.perlmonks.org/?node_id=680842 */
+static char **
+XS_unpack_charPtrPtr (SV *arg) {
+ char **ret;
+ AV *av;
+ I32 i;
+
+ if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
+ croak (\"array reference expected\");
+
+ av = (AV *)SvRV (arg);
+ ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
+ if (!ret)
+ croak (\"malloc failed\");
+
+ for (i = 0; i <= av_len (av); i++) {
+ SV **elem = av_fetch (av, i, 0);
+
+ if (!elem || !*elem)
+ croak (\"missing element in list\");
+
+ ret[i] = SvPV_nolen (*elem);
+ }
+
+ ret[i] = NULL;
+
+ return ret;
+}
+#endif
+
+/* Handle set_values parameter. */
+typedef struct pl_set_values {
+ size_t nr_values;
+ hive_set_value *values;
+} pl_set_values;
+
+static pl_set_values
+unpack_pl_set_values (SV *sv)
+{
+ pl_set_values ret;
+ AV *av;
+ I32 i;
+
+ if (!sv || !SvOK (sv) || !SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV)
+ croak (\"array reference expected\");
+
+ av = (AV *)SvRV(sv);
+ ret.nr_values = av_len (av) + 1;
+ ret.values = malloc (ret.nr_values * sizeof (hive_set_value));
+ if (!ret.values)
+ croak (\"malloc failed\");
+
+ for (i = 0; i <= av_len (av); i++) {
+ SV **hvp = av_fetch (av, i, 0);
+
+ if (!hvp || !*hvp || !SvROK (*hvp) || SvTYPE (SvRV (*hvp)) != SVt_PVHV)
+ croak (\"missing element in list or not a hash ref\");
+
+ HV *hv = (HV *)SvRV(*hvp);
+
+ SV **svp;
+ svp = hv_fetch (hv, \"key\", 3, 0);
+ if (!svp || !*svp)
+ croak (\"missing 'key' in hash\");
+ ret.values[i].key = SvPV_nolen (*svp);
+
+ svp = hv_fetch (hv, \"t\", 1, 0);
+ if (!svp || !*svp)
+ croak (\"missing 't' in hash\");
+ ret.values[i].t = SvIV (*svp);
+
+ svp = hv_fetch (hv, \"value\", 5, 0);
+ if (!svp || !*svp)
+ croak (\"missing 'value' in hash\");
+ ret.values[i].value = SvPV (*svp, ret.values[i].len);
+ }
+
+ return ret;
+}
+
+MODULE = Win::Hivex PACKAGE = Win::Hivex
+
+PROTOTYPES: ENABLE
+
+hive_h *
+_open (filename, flags)
+ char *filename;
+ int flags;
+ CODE:
+ RETVAL = hivex_open (filename, flags);
+ if (!RETVAL)
+ croak (\"hivex_open: %%s: %%s\", filename, strerror (errno));
+ OUTPUT:
+ RETVAL
+
+void
+DESTROY (h)
+ hive_h *h;
+ PPCODE:
+ if (hivex_close (h) == -1)
+ croak (\"hivex_close: %%s\", strerror (errno));
+
+";
+
+ List.iter (
+ fun (name, style, _, longdesc) ->
+ (* The close and open calls are handled specially above. *)
+ if fst style <> RErrDispose && List.hd (snd style) = AHive then (
+ (match fst style with
+ | RErr -> pr "void\n"
+ | RErrDispose -> failwith "perl bindings cannot handle a call which disposes of the handle"
+ | RHive -> failwith "perl bindings cannot handle a call which returns a handle"
+ | RNode
+ | RNodeNotFound
+ | RValue
+ | RString -> pr "SV *\n"
+ | RNodeList
+ | RValueList
+ | RStringList
+ | RLenType
+ | RLenTypeVal -> pr "void\n"
+ | RInt32 -> pr "SV *\n"
+ | RInt64 -> pr "SV *\n"
+ );
+
+ (* Call and arguments. *)
+ let perl_params =
+ filter_map (function
+ | AUnusedFlags -> None
+ | arg -> Some (name_of_argt arg)) (snd style) in
+
+ let c_params =
+ List.map (function
+ | AUnusedFlags -> "0"
+ | ASetValues -> "values.nr_values, values.values"
+ | arg -> name_of_argt arg) (snd style) in
+
+ pr "%s (%s)\n" name (String.concat ", " perl_params);
+ iteri (
+ fun i ->
+ function
+ | AHive ->
+ pr " hive_h *h;\n"
+ | ANode n
+ | AValue n ->
+ pr " int %s;\n" n
+ | AString n ->
+ pr " char *%s;\n" n
+ | AStringNullable n ->
+ (* http://www.perlmonks.org/?node_id=554277 *)
+ pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n i i
+ | AOpenFlags ->
+ pr " int flags;\n"
+ | AUnusedFlags -> ()
+ | ASetValues ->
+ pr " pl_set_values values = unpack_pl_set_values (ST(%d));\n" i
+ ) (snd style);
+
+ let free_args () =
+ List.iter (
+ function
+ | ASetValues ->
+ pr " free (values.values);\n"
+ | AHive | ANode _ | AValue _ | AString _ | AStringNullable _
+ | AOpenFlags | AUnusedFlags -> ()
+ ) (snd style)
+ in
+
+ (* Code. *)
+ (match fst style with
+ | RErr ->
+ pr "PREINIT:\n";
+ pr " int r;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == -1)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+
+ | RErrDispose -> assert false
+ | RHive -> assert false
+
+ | RInt32
+ | RNode
+ | RValue ->
+ pr "PREINIT:\n";
+ pr " /* hive_node_h = hive_value_h = size_t so we cheat\n";
+ pr " here to simplify the generator */\n";
+ pr " size_t r;\n";
+ pr " CODE:\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == 0)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " RETVAL = newSViv (r);\n";
+ pr " OUTPUT:\n";
+ pr " RETVAL\n"
+
+ | RNodeNotFound ->
+ pr "PREINIT:\n";
+ pr " hive_node_h r;\n";
+ pr " CODE:\n";
+ pr " errno = 0;\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == 0 && errno != 0)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " if (r == 0)\n";
+ pr " RETVAL = &PL_sv_undef;\n";
+ pr " else\n";
+ pr " RETVAL = newSViv (r);\n";
+ pr " OUTPUT:\n";
+ pr " RETVAL\n"
+
+ | RString ->
+ pr "PREINIT:\n";
+ pr " char *r;\n";
+ pr " CODE:\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == NULL)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " RETVAL = newSVpv (r, 0);\n";
+ pr " free (r);\n";
+ pr " OUTPUT:\n";
+ pr " RETVAL\n"
+
+ | RNodeList
+ | RValueList ->
+ pr "PREINIT:\n";
+ pr " size_t *r;\n";
+ pr " int i, n;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == NULL)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " for (n = 0; r[n] != 0; ++n) /**/;\n";
+ pr " EXTEND (SP, n);\n";
+ pr " for (i = 0; i < n; ++i)\n";
+ pr " PUSHs (sv_2mortal (newSViv (r[i])));\n";
+ pr " free (r);\n";
+
+ | RStringList ->
+ pr "PREINIT:\n";
+ pr " char **r;\n";
+ pr " int i, n;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == NULL)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " for (n = 0; r[n] != NULL; ++n) /**/;\n";
+ pr " EXTEND (SP, n);\n";
+ pr " for (i = 0; i < n; ++i) {\n";
+ pr " PUSHs (sv_2mortal (newSVpv (r[i], 0)));\n";
+ pr " free (r[i]);\n";
+ pr " }\n";
+ pr " free (r);\n";
+
+ | RLenType ->
+ pr "PREINIT:\n";
+ pr " int r;\n";
+ pr " size_t len;\n";
+ pr " hive_type type;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s, &len, &type);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == -1)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " EXTEND (SP, 2);\n";
+ pr " PUSHs (sv_2mortal (newSViv (type)));\n";
+ pr " PUSHs (sv_2mortal (newSViv (len)));\n";
+
+ | RLenTypeVal ->
+ pr "PREINIT:\n";
+ pr " char *r;\n";
+ pr " size_t len;\n";
+ pr " hive_type type;\n";
+ pr " PPCODE:\n";
+ pr " r = hivex_%s (%s, &len, &type);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == NULL)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " EXTEND (SP, 2);\n";
+ pr " PUSHs (sv_2mortal (newSViv (type)));\n";
+ pr " PUSHs (sv_2mortal (newSVpv (r, len)));\n";
+ pr " free (r);\n";
+
+ | RInt64 ->
+ pr "PREINIT:\n";
+ pr " int64_t r;\n";
+ pr " CODE:\n";
+ pr " errno = 0;\n";
+ pr " r = hivex_%s (%s);\n"
+ name (String.concat ", " c_params);
+ free_args ();
+ pr " if (r == -1 && errno != 0)\n";
+ pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
+ name;
+ pr " RETVAL = my_newSVll (r);\n";
+ pr " OUTPUT:\n";
+ pr " RETVAL\n"
+ );
+ pr "\n"
+ )
+ ) functions