RHEL 5: Detect endianness functions and supply them.
[libguestfs.git] / hivex / hivexml.c
1 /* hivexml - Convert Windows Registry "hive" to XML file.
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 #include <libxml/xmlwriter.h>
30
31 #include "hivex.h"
32
33 /* Callback functions. */
34 static int node_start (hive_h *, void *, hive_node_h, const char *name);
35 static int node_end (hive_h *, void *, hive_node_h, const char *name);
36 static int value_string (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
37 static int value_multiple_strings (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
38 static int value_string_invalid_utf16 (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
39 static int value_dword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
40 static int value_qword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
41 static int value_binary (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
42 static int value_none (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
43 static int value_other (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
44
45 static struct hivex_visitor visitor = {
46   .node_start = node_start,
47   .node_end = node_end,
48   .value_string = value_string,
49   .value_multiple_strings = value_multiple_strings,
50   .value_string_invalid_utf16 = value_string_invalid_utf16,
51   .value_dword = value_dword,
52   .value_qword = value_qword,
53   .value_binary = value_binary,
54   .value_none = value_none,
55   .value_other = value_other
56 };
57
58 #define XML_CHECK(proc, args)                                           \
59   do {                                                                  \
60     if ((proc args) == -1) {                                            \
61       fprintf (stderr, "%s: failed to write XML document\n", #proc);    \
62       exit (1);                                                         \
63     }                                                                   \
64   } while (0)
65
66 int
67 main (int argc, char *argv[])
68 {
69   int c;
70   int open_flags = 0;
71   int visit_flags = 0;
72
73   while ((c = getopt (argc, argv, "dk")) != EOF) {
74     switch (c) {
75     case 'd':
76       open_flags |= HIVEX_OPEN_DEBUG;
77       break;
78     case 'k':
79       visit_flags |= HIVEX_VISIT_SKIP_BAD;
80       break;
81     default:
82       fprintf (stderr, "hivexml [-dk] regfile > output.xml\n");
83       exit (1);
84     }
85   }
86
87   if (optind + 1 != argc) {
88     fprintf (stderr, "hivexml: missing name of input file\n");
89     exit (1);
90   }
91
92   hive_h *h = hivex_open (argv[optind], open_flags);
93   if (h == NULL) {
94     perror (argv[optind]);
95     exit (1);
96   }
97
98   /* Note both this macro, and xmlTextWriterStartDocument leak memory.  There
99    * doesn't seem to be any way to recover that memory, but it's not a
100    * large amount.
101    */
102   LIBXML_TEST_VERSION;
103
104   xmlTextWriterPtr writer;
105   writer = xmlNewTextWriterFilename ("/dev/stdout", 0);
106   if (writer == NULL) {
107     fprintf (stderr, "xmlNewTextWriterFilename: failed to create XML writer\n");
108     exit (1);
109   }
110
111   XML_CHECK (xmlTextWriterStartDocument, (writer, NULL, "utf-8", NULL));
112   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "hive"));
113
114   if (hivex_visit (h, &visitor, sizeof visitor, writer, visit_flags) == -1) {
115     perror (argv[optind]);
116     exit (1);
117   }
118
119   if (hivex_close (h) == -1) {
120     perror (argv[optind]);
121     exit (1);
122   }
123
124   XML_CHECK (xmlTextWriterEndElement, (writer));
125   XML_CHECK (xmlTextWriterEndDocument, (writer));
126   xmlFreeTextWriter (writer);
127
128   exit (0);
129 }
130
131 static int
132 node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
133 {
134   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
135   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
136   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
137   return 0;
138 }
139
140 static int
141 node_end (hive_h *h, void *writer_v, hive_node_h node, const char *name)
142 {
143   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
144   XML_CHECK (xmlTextWriterEndElement, (writer));
145   return 0;
146 }
147
148 static void
149 start_value (xmlTextWriterPtr writer,
150              const char *key, const char *type, const char *encoding)
151 {
152   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
153   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
154   if (encoding)
155     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
156   if (*key)
157     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
158   else                          /* default key */
159     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
160 }
161
162 static void
163 end_value (xmlTextWriterPtr writer)
164 {
165   XML_CHECK (xmlTextWriterEndElement, (writer));
166 }
167
168 static int
169 value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
170               hive_type t, size_t len, const char *key, const char *str)
171 {
172   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
173   const char *type;
174
175   switch (t) {
176   case hive_t_string: type = "string"; break;
177   case hive_t_expand_string: type = "expand"; break;
178   case hive_t_link: type = "link"; break;
179
180   case hive_t_none:
181   case hive_t_binary:
182   case hive_t_dword:
183   case hive_t_dword_be:
184   case hive_t_multiple_strings:
185   case hive_t_resource_list:
186   case hive_t_full_resource_description:
187   case hive_t_resource_requirements_list:
188   case hive_t_qword:
189     abort ();                   /* internal error - should not happen */
190
191   default:
192     type = "unknown";
193   }
194
195   start_value (writer, key, type, NULL);
196   XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
197   end_value (writer);
198   return 0;
199 }
200
201 static int
202 value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
203                         hive_value_h value, hive_type t, size_t len,
204                         const char *key, char **argv)
205 {
206   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
207   start_value (writer, key, "string-list", NULL);
208
209   size_t i;
210   for (i = 0; argv[i] != NULL; ++i) {
211     XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
212     XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
213     XML_CHECK (xmlTextWriterEndElement, (writer));
214   }
215
216   end_value (writer);
217   return 0;
218 }
219
220 static int
221 value_string_invalid_utf16 (hive_h *h, void *writer_v, hive_node_h node,
222                             hive_value_h value, hive_type t, size_t len,
223                             const char *key,
224                             const char *str /* original data */)
225 {
226   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
227   const char *type;
228
229   switch (t) {
230   case hive_t_string: type = "bad-string"; break;
231   case hive_t_expand_string: type = "bad-expand"; break;
232   case hive_t_link: type = "bad-link"; break;
233   case hive_t_multiple_strings: type = "bad-string-list"; break;
234
235   case hive_t_none:
236   case hive_t_binary:
237   case hive_t_dword:
238   case hive_t_dword_be:
239   case hive_t_resource_list:
240   case hive_t_full_resource_description:
241   case hive_t_resource_requirements_list:
242   case hive_t_qword:
243     abort ();                   /* internal error - should not happen */
244
245   default:
246     type = "unknown";
247   }
248
249   start_value (writer, key, type, "base64");
250   XML_CHECK (xmlTextWriterWriteBase64, (writer, str, 0, len));
251   end_value (writer);
252
253   return 0;
254 }
255
256 static int
257 value_dword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
258              hive_type t, size_t len, const char *key, int32_t v)
259 {
260   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
261   start_value (writer, key, "int32", NULL);
262   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi32, v));
263   end_value (writer);
264   return 0;
265 }
266
267 static int
268 value_qword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
269              hive_type t, size_t len, const char *key, int64_t v)
270 {
271   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
272   start_value (writer, key, "int64", NULL);
273   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi64, v));
274   end_value (writer);
275   return 0;
276 }
277
278 static int
279 value_binary (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
280               hive_type t, size_t len, const char *key, const char *v)
281 {
282   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
283   start_value (writer, key, "binary", "base64");
284   XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
285   end_value (writer);
286   return 0;
287 }
288
289 static int
290 value_none (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
291             hive_type t, size_t len, const char *key, const char *v)
292 {
293   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
294   start_value (writer, key, "none", "base64");
295   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
296   end_value (writer);
297   return 0;
298 }
299
300 static int
301 value_other (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
302              hive_type t, size_t len, const char *key, const char *v)
303 {
304   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
305   const char *type;
306
307   switch (t) {
308   case hive_t_none:
309   case hive_t_binary:
310   case hive_t_dword:
311   case hive_t_dword_be:
312   case hive_t_qword:
313   case hive_t_string:
314   case hive_t_expand_string:
315   case hive_t_link:
316   case hive_t_multiple_strings:
317     abort ();                   /* internal error - should not happen */
318
319   case hive_t_resource_list: type = "resource-list"; break;
320   case hive_t_full_resource_description: type = "resource-description"; break;
321   case hive_t_resource_requirements_list: type = "resource-requirements"; break;
322
323   default:
324     type = "unknown";
325   }
326
327   start_value (writer, key, type, "base64");
328   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
329   end_value (writer);
330
331   return 0;
332 }