diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-08-29 13:01:53 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-08-29 17:08:01 +0100 |
commit | 288cc74d77fd80e40a442344d9d0ce00162c1fb4 (patch) | |
tree | c43ecaeed97566746915990fd4899cc7a71f8725 /src/inspect-fs-windows.c | |
parent | 8a723ca62eb4f93f19c5c66beffaf70997afb64c (diff) | |
download | libguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.tar.gz libguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.tar.xz libguestfs-288cc74d77fd80e40a442344d9d0ce00162c1fb4.zip |
New API: guestfs_hivex_value_utf8
A convenience function that reads a value from the registry
and returns it as UTF-8.
Diffstat (limited to 'src/inspect-fs-windows.c')
-rw-r--r-- | src/inspect-fs-windows.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c index d04024bc..cd2bd6ca 100644 --- a/src/inspect-fs-windows.c +++ b/src/inspect-fs-windows.c @@ -27,6 +27,7 @@ #include <string.h> #include <sys/stat.h> #include <errno.h> +#include <iconv.h> #ifdef HAVE_ENDIAN_H #include <endian.h> @@ -587,3 +588,87 @@ guestfs___case_sensitive_path_silently (guestfs_h *g, const char *path) g->error_cb = old_error_cb; return ret; } + +/* Read the data from 'valueh', assume it is UTF16LE and convert it to + * UTF8. This is copied from hivex_value_string which doesn't work in + * the appliance because it uses iconv_open which doesn't work because + * we delete all the i18n databases. + */ +static char *utf16_to_utf8 (/* const */ char *input, size_t len); + +char * +guestfs__hivex_value_utf8 (guestfs_h *g, int64_t valueh) +{ + char *buf, *ret; + size_t buflen; + + buf = guestfs_hivex_value_value (g, valueh, &buflen); + if (buf == NULL) + return NULL; + + ret = utf16_to_utf8 (buf, buflen); + if (ret == NULL) { + perrorf (g, "hivex: conversion of registry value to UTF8 failed"); + free (buf); + return NULL; + } + free (buf); + + return ret; +} + +static char * +utf16_to_utf8 (/* const */ char *input, size_t len) +{ + iconv_t ic = iconv_open ("UTF-8", "UTF-16"); + if (ic == (iconv_t) -1) + return NULL; + + /* iconv(3) has an insane interface ... */ + + /* Mostly UTF-8 will be smaller, so this is a good initial guess. */ + size_t outalloc = len; + + again:; + size_t inlen = len; + size_t outlen = outalloc; + char *out = malloc (outlen + 1); + if (out == NULL) { + int err = errno; + iconv_close (ic); + errno = err; + return NULL; + } + char *inp = input; + char *outp = out; + + size_t r = iconv (ic, &inp, &inlen, &outp, &outlen); + if (r == (size_t) -1) { + if (errno == E2BIG) { + int err = errno; + size_t prev = outalloc; + /* Try again with a larger output buffer. */ + free (out); + outalloc *= 2; + if (outalloc < prev) { + iconv_close (ic); + errno = err; + return NULL; + } + goto again; + } + else { + /* Else some conversion failure, eg. EILSEQ, EINVAL. */ + int err = errno; + iconv_close (ic); + free (out); + errno = err; + return NULL; + } + } + + *outp = '\0'; + iconv_close (ic); + + return out; +} |