4 * Deals with the XML information in WIM files. Uses the C library libxml2.
8 * Copyright (C) 2012 Eric Biggers
10 * This file is part of wimlib, a library for working with WIM files.
12 * wimlib is free software; you can redistribute it and/or modify it under the
13 * terms of the GNU Lesser General Public License as published by the Free
14 * Software Foundation; either version 2.1 of the License, or (at your option)
17 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
19 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with wimlib; if not, see http://www.gnu.org/licenses/.
26 #include "wimlib_internal.h"
29 #include "timestamp.h"
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34 #include <libxml/xmlwriter.h>
36 /* Structures used to form an in-memory representation of the XML data (other
37 * than the raw parse tree from libxml). */
39 struct windows_version {
51 char *installation_type;
56 char *default_language;
59 bool windows_version_exists;
60 struct windows_version windows_version;
70 u64 last_modification_time;
71 bool windows_info_exists;
72 struct windows_info windows_info;
76 char *display_description;
81 /* Returns a statically allocated string that is a string representation of the
82 * architecture number. */
83 static const char *get_arch(int arch)
93 /* XXX Are there other arch values? */
95 snprintf(buf, sizeof(buf), "%d (unknown)", arch);
101 /* Iterate through the children of an xmlNode. */
102 #define for_node_child(parent, child) \
103 for (child = parent->children; child != NULL; child = child->next)
105 /* Utility functions for xmlNodes */
106 static inline bool node_is_element(xmlNode *node)
108 return node->type == XML_ELEMENT_NODE;
111 static inline bool node_is_text(xmlNode *node)
113 return node->type == XML_TEXT_NODE;
116 static inline bool node_is_attribute(xmlNode *node)
118 return node->type == XML_ATTRIBUTE_NODE;
121 static inline bool node_name_is(xmlNode *node, const char *name)
123 /* For now, both upper case and lower case element names are accepted. */
124 return strcasecmp((const char *)node->name, name) == 0;
127 /* Finds the text node that is a child of an element node and returns its
128 * content converted to a 64-bit unsigned integer. Returns 0 if no text node is
130 static u64 node_get_u64(const xmlNode *u64_node)
133 for_node_child(u64_node, child)
134 if (node_is_text(child))
135 return strtoull((const char *)child->content, NULL, 10);
139 /* Like node_get_u64(), but expects a number in base 16. */
140 static u64 node_get_hex_u64(const xmlNode *u64_node)
143 for_node_child(u64_node, child)
144 if (node_is_text(child))
145 return strtoull(child->content, NULL, 16);
149 static int node_get_string(const xmlNode *string_node, char **str)
154 for_node_child(string_node, child) {
155 if (node_is_text(child) && child->content) {
156 p = STRDUP(child->content);
158 ERROR("Out of memory");
159 return WIMLIB_ERR_NOMEM;
168 /* Returns the timestamp from a time node. It has child elements <HIGHPART> and
169 * <LOWPART> that are then used to construct a 64-bit timestamp. */
170 static u64 node_get_timestamp(const xmlNode *time_node)
175 for_node_child(time_node, child) {
176 if (!node_is_element(child))
178 if (node_name_is(child, "HIGHPART"))
179 high_part = node_get_hex_u64(child);
180 else if (node_name_is(child, "LOWPART"))
181 low_part = node_get_hex_u64(child);
183 return (u64)low_part | ((u64)high_part << 32);
186 /* Used to sort an array of struct image_infos by their image indices. */
187 static int sort_by_index(const void *p1, const void *p2)
189 u64 index_1 = ((struct image_info*)p1)->index;
190 u64 index_2 = ((struct image_info*)p1)->index;
191 if (index_1 < index_2)
193 else if (index_1 > index_2)
200 /* Frees memory allocated inside a struct windows_info structure. */
201 static void destroy_windows_info(struct windows_info *windows_info)
205 FREE(windows_info->product_name);
206 FREE(windows_info->edition_id);
207 FREE(windows_info->installation_type);
208 FREE(windows_info->product_type);
209 for (i = 0; i < windows_info->num_languages; i++)
210 FREE(windows_info->languages[i]);
211 FREE(windows_info->languages);
212 FREE(windows_info->system_root);
215 /* Frees memory allocated inside a struct image_info structure. */
216 static void destroy_image_info(struct image_info *image_info)
218 FREE(image_info->name);
219 FREE(image_info->description);
220 FREE(image_info->flags);
221 FREE(image_info->display_name);
222 FREE(image_info->display_description);
223 destroy_windows_info(&image_info->windows_info);
224 memset(image_info, 0, sizeof(struct image_info));
227 void free_wim_info(struct wim_info *info)
232 for (i = 0; i < info->num_images; i++)
233 destroy_image_info(&info->images[i]);
240 /* Reads the information from a <VERSION> element inside the <WINDOWS> element.
242 static void xml_read_windows_version(const xmlNode *version_node,
243 struct windows_version* windows_version)
246 for_node_child(version_node, child) {
247 if (!node_is_element(child))
249 if (node_name_is(child, "MAJOR"))
250 windows_version->major = node_get_u64(child);
251 else if (node_name_is(child, "MINOR"))
252 windows_version->minor = node_get_u64(child);
253 else if (node_name_is(child, "BUILD"))
254 windows_version->build = node_get_u64(child);
255 else if (node_name_is(child, "SPBUILD"))
256 windows_version->sp_build = node_get_u64(child);
257 else if (node_name_is(child, "SPLEVEL"))
258 windows_version->sp_level = node_get_u64(child);
262 /* Reads the information from a <LANGUAGE> element inside a <WINDOWS> element.
264 static int xml_read_languages(const xmlNode *languages_node,
265 char ***languages_ret,
266 u64 *num_languages_ret,
267 char **default_language_ret)
276 for_node_child(languages_node, child)
277 if (node_is_element(child) && node_name_is(child, "LANGUAGE"))
280 languages = CALLOC(num_languages, sizeof(char*));
282 ERROR("Out of memory");
283 return WIMLIB_ERR_NOMEM;
286 *languages_ret = languages;
287 *num_languages_ret = num_languages;
291 for_node_child(languages_node, child) {
292 if (!node_is_element(child))
294 if (node_name_is(child, "LANGUAGE"))
295 ret = node_get_string(child, &languages[i++]);
296 else if (node_name_is(child, "DEFAULT"))
297 ret = node_get_string(child, default_language_ret);
304 /* Reads the information from a <WINDOWS> element inside an <IMAGE> element. */
305 static int xml_read_windows_info(const xmlNode *windows_node,
306 struct windows_info *windows_info)
311 for_node_child(windows_node, child) {
312 if (!node_is_element(child))
314 if (node_name_is(child, "ARCH")) {
315 windows_info->arch = node_get_u64(child);
316 } else if (node_name_is(child, "PRODUCTNAME")) {
317 ret = node_get_string(child,
318 &windows_info->product_name);
319 } else if (node_name_is(child, "EDITIONID")) {
320 ret = node_get_string(child,
321 &windows_info->edition_id);
322 } else if (node_name_is(child, "INSTALLATIONTYPE")) {
323 ret = node_get_string(child,
324 &windows_info->installation_type);
325 } else if (node_name_is(child, "PRODUCTTYPE")) {
326 ret = node_get_string(child,
327 &windows_info->product_type);
328 } else if (node_name_is(child, "PRODUCTSUITE")) {
329 ret = node_get_string(child,
330 &windows_info->product_suite);
331 } else if (node_name_is(child, "LANGUAGES")) {
332 ret = xml_read_languages(child,
333 &windows_info->languages,
334 &windows_info->num_languages,
335 &windows_info->default_language);
336 } else if (node_name_is(child, "VERSION")) {
337 xml_read_windows_version(child,
338 &windows_info->windows_version);
339 windows_info->windows_version_exists = true;
340 } else if (node_name_is(child, "SYSTEMROOT")) {
341 ret = node_get_string(child, &windows_info->system_root);
342 } else if (node_name_is(child, "HAL")) {
343 ret = node_get_string(child, &windows_info->hal);
352 /* Reads the information from an <IMAGE> element. */
353 static int xml_read_image_info(xmlNode *image_node,
354 struct image_info *image_info)
360 index_prop = xmlGetProp(image_node, "INDEX");
363 image_info->index = strtoul(index_prop, &tmp, 10);
366 image_info->index = 0;
370 for_node_child(image_node, child) {
371 if (!node_is_element(child))
373 if (node_name_is(child, "DIRCOUNT"))
374 image_info->dir_count = node_get_u64(child);
375 else if (node_name_is(child, "FILECOUNT"))
376 image_info->file_count = node_get_u64(child);
377 else if (node_name_is(child, "TOTALBYTES"))
378 image_info->total_bytes = node_get_u64(child);
379 else if (node_name_is(child, "HARDLINKBYTES"))
380 image_info->hard_link_bytes = node_get_u64(child);
381 else if (node_name_is(child, "CREATIONTIME"))
382 image_info->creation_time = node_get_timestamp(child);
383 else if (node_name_is(child, "LASTMODIFICATIONTIME"))
384 image_info->last_modification_time = node_get_timestamp(child);
385 else if (node_name_is(child, "WINDOWS")) {
386 DEBUG("Found <WINDOWS> tag");
387 ret = xml_read_windows_info(child,
388 &image_info->windows_info);
389 image_info->windows_info_exists = true;
390 } else if (node_name_is(child, "NAME")) {
391 ret = node_get_string(child, &image_info->name);
392 } else if (node_name_is(child, "DESCRIPTION")) {
393 ret = node_get_string(child, &image_info->description);
394 } else if (node_name_is(child, "FLAGS")) {
395 ret = node_get_string(child, &image_info->flags);
396 } else if (node_name_is(child, "DISPLAYNAME")) {
397 ret = node_get_string(child, &image_info->display_name);
398 } else if (node_name_is(child, "DISPLAYDESCRIPTION")) {
399 ret = node_get_string(child, &image_info->display_description);
404 if (!image_info->name) {
405 WARNING("Image with index %"PRIu64" has no name",
407 image_info->name = MALLOC(1);
408 if (!image_info->name) {
409 ERROR("Out of memory");
410 return WIMLIB_ERR_NOMEM;
412 image_info->name[0] = '\0';
417 /* Reads the information from a <WIM> element, which should be the root element
418 * of the XML tree. */
419 static int xml_read_wim_info(const xmlNode *wim_node,
420 struct wim_info **wim_info_ret)
422 struct wim_info *wim_info;
426 struct image_info *cur_image_info;
428 wim_info = CALLOC(1, sizeof(struct wim_info));
430 ERROR("Out of memory");
431 return WIMLIB_ERR_NOMEM;
434 /* Count how many images there are. */
436 for_node_child(wim_node, child)
437 if (node_is_element(child) && node_name_is(child, "IMAGE"))
443 /* Allocate the array of struct image_infos and fill them in. */
444 wim_info->images = CALLOC(num_images, sizeof(wim_info->images[0]));
445 if (!wim_info->images) {
446 ret = WIMLIB_ERR_NOMEM;
447 ERROR("Out of memory!");
450 wim_info->num_images = num_images;
451 cur_image_info = wim_info->images;
452 for_node_child(wim_node, child) {
453 if (!node_is_element(child))
455 if (node_name_is(child, "IMAGE")) {
456 DEBUG("Found <IMAGE> tag");
457 ret = xml_read_image_info(child, cur_image_info++);
460 } else if (node_name_is(child, "TOTALBYTES")) {
461 wim_info->total_bytes = node_get_u64(child);
465 /* Sort the array of struct image_infos by image index. */
466 qsort(wim_info->images, wim_info->num_images,
467 sizeof(struct image_info), sort_by_index);
469 *wim_info_ret = wim_info;
472 free_wim_info(wim_info);
476 /* Prints the information contained in a struct windows_info structure. */
477 static void print_windows_info(const struct windows_info *windows_info)
480 const struct windows_version *windows_version;
482 printf("Architecture: %s\n", get_arch(windows_info->arch));
483 printf("Product Name: %s\n", windows_info->product_name);
484 printf("Edition ID: %s\n", windows_info->edition_id);
485 printf("Installation Type: %s\n", windows_info->installation_type);
486 if (windows_info->hal)
487 printf("HAL: %s\n", windows_info->hal);
488 printf("Product Type: %s\n", windows_info->product_type);
489 if (windows_info->product_suite)
490 printf("Product Suite: %s\n", windows_info->product_suite);
491 printf("Languages: ");
492 for (i = 0; i < windows_info->num_languages; i++) {
493 fputs(windows_info->languages[i], stdout);
497 printf("Default Language: %s\n", windows_info->default_language);
498 printf("System Root: %s\n", windows_info->system_root);
499 if (windows_info->windows_version_exists) {
500 windows_version = &windows_info->windows_version;
501 printf("Major Version: %"PRIu64"\n",
502 windows_version->major);
503 printf("Minor Version: %"PRIu64"\n",
504 windows_version->minor);
505 printf("Build: %"PRIu64"\n",
506 windows_version->build);
507 printf("Service Pack Build: %"PRIu64"\n",
508 windows_version->sp_build);
509 printf("Service Pack Level: %"PRIu64"\n",
510 windows_version->sp_level);
515 /* Writes the information contained in a struct windows_version structure to the XML
516 * document being constructed in memory. This is the <VERSION> element inside
517 * the <WINDOWS> element. */
518 static int xml_write_windows_version(xmlTextWriter *writer,
519 const struct windows_version *version)
522 rc = xmlTextWriterStartElement(writer, "VERSION");
526 rc = xmlTextWriterWriteFormatElement(writer, "MAJOR", "%"PRIu64,
531 rc = xmlTextWriterWriteFormatElement(writer, "MINOR", "%"PRIu64,
536 rc = xmlTextWriterWriteFormatElement(writer, "BUILD", "%"PRIu64,
541 rc = xmlTextWriterWriteFormatElement(writer, "SPBUILD", "%"PRIu64,
546 rc = xmlTextWriterWriteFormatElement(writer, "SPLEVEL", "%"PRIu64,
551 return xmlTextWriterEndElement(writer); /* </VERSION> */
554 /* Writes the information contained in a struct windows_info structure to the XML
555 * document being constructed in memory. This is the <WINDOWS> element. */
556 static int xml_write_windows_info(xmlTextWriter *writer,
557 const struct windows_info *windows_info)
560 rc = xmlTextWriterStartElement(writer, "WINDOWS");
565 rc = xmlTextWriterWriteFormatElement(writer, "ARCH", "%"PRIu64,
570 if (windows_info->product_name) {
571 rc = xmlTextWriterWriteElement(writer, "PRODUCTNAME",
572 windows_info->product_name);
577 if (windows_info->edition_id) {
578 rc = xmlTextWriterWriteElement(writer, "EDITIONID",
579 windows_info->edition_id);
584 if (windows_info->installation_type) {
585 rc = xmlTextWriterWriteElement(writer, "INSTALLATIONTYPE",
586 windows_info->installation_type);
591 if (windows_info->hal) {
592 rc = xmlTextWriterWriteElement(writer, "HAL",
598 if (windows_info->system_root) {
599 rc = xmlTextWriterWriteElement(writer, "SYSTEMROOT",
600 windows_info->system_root);
605 if (windows_info->product_type) {
606 rc = xmlTextWriterWriteElement(writer, "PRODUCTTYPE",
607 windows_info->product_type);
612 if (windows_info->product_suite) {
613 rc = xmlTextWriterWriteElement(writer, "PRODUCTSUITE",
614 windows_info->product_suite);
619 if (windows_info->num_languages) {
620 rc = xmlTextWriterStartElement(writer, "LANGUAGES");
624 for (int i = 0; i < windows_info->num_languages; i++) {
625 rc = xmlTextWriterWriteElement(writer, "LANGUAGE",
626 windows_info->languages[i]);
630 rc = xmlTextWriterWriteElement(writer, "DEFAULT",
631 windows_info->default_language);
635 rc = xmlTextWriterEndElement(writer); /* </LANGUAGES> */
640 if (windows_info->windows_version_exists) {
641 rc = xml_write_windows_version(writer, &windows_info->windows_version);
646 return xmlTextWriterEndElement(writer); /* </WINDOWS> */
649 /* Writes a time element to the XML document being constructed in memory. */
650 static int xml_write_time(xmlTextWriter *writer, const char *element_name,
654 rc = xmlTextWriterStartElement(writer, element_name);
658 rc = xmlTextWriterWriteFormatElement(writer, "HIGHPART",
659 "0x%"PRIX32, (u32)(time >> 32));
663 rc = xmlTextWriterWriteFormatElement(writer, "LOWPART",
664 "0x%"PRIX32, (u32)time);
668 rc = xmlTextWriterEndElement(writer); /* </@element_name> */
675 /* Writes an <IMAGE> element to the XML document. */
676 static int xml_write_image_info(xmlTextWriter *writer,
677 const struct image_info *image_info)
680 rc = xmlTextWriterStartElement(writer, "IMAGE");
684 rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%"PRIu64,
689 rc = xmlTextWriterWriteFormatElement(writer, "DIRCOUNT", "%"PRIu64,
690 image_info->dir_count);
694 rc = xmlTextWriterWriteFormatElement(writer, "FILECOUNT", "%"PRIu64,
695 image_info->file_count);
699 rc = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
700 image_info->total_bytes);
704 rc = xmlTextWriterWriteFormatElement(writer, "HARDLINKBYTES", "%"PRIu64,
705 image_info->hard_link_bytes);
709 rc = xml_write_time(writer, "CREATIONTIME",
710 image_info->creation_time);
714 rc = xml_write_time(writer, "LASTMODIFICATIONTIME",
715 image_info->last_modification_time);
719 if (image_info->windows_info_exists) {
720 rc = xml_write_windows_info(writer, &image_info->windows_info);
724 DEBUG("<WINDOWS> tag does not exist.");
727 if (image_info->name) {
728 rc = xmlTextWriterWriteElement(writer, "NAME", image_info->name);
732 if (image_info->description) {
733 rc = xmlTextWriterWriteElement(writer, "DESCRIPTION",
734 image_info->description);
738 if (image_info->display_name) {
739 rc = xmlTextWriterWriteElement(writer, "DISPLAYNAME",
740 image_info->display_name);
744 if (image_info->display_description) {
745 rc = xmlTextWriterWriteElement(writer, "DISPLAYDESCRIPTION",
746 image_info->display_description);
751 if (image_info->flags) {
752 rc = xmlTextWriterWriteElement(writer, "FLAGS",
758 return xmlTextWriterEndElement(writer); /* </IMAGE> */
763 /* Makes space for another image in the XML information and return a pointer to
765 static struct image_info *add_image_info_struct(struct wim_info *wim_info)
767 struct image_info *images;
769 images = CALLOC(wim_info->num_images + 1, sizeof(struct image_info));
772 memcpy(images, wim_info->images,
773 wim_info->num_images * sizeof(struct image_info));
774 FREE(wim_info->images);
775 wim_info->images = images;
776 wim_info->num_images++;
777 return &images[wim_info->num_images - 1];
780 static int clone_windows_info(const struct windows_info *old,
781 struct windows_info *new)
785 if (old->product_name && !(new->product_name = STRDUP(old->product_name)))
786 return WIMLIB_ERR_NOMEM;
787 if (old->edition_id && !(new->edition_id = STRDUP(old->edition_id)))
788 return WIMLIB_ERR_NOMEM;
789 if (old->installation_type && !(new->installation_type =
790 STRDUP(old->installation_type)))
791 return WIMLIB_ERR_NOMEM;
792 if (old->hal && !(new->hal = STRDUP(old->hal)))
793 return WIMLIB_ERR_NOMEM;
794 if (old->product_type && !(new->product_type = STRDUP(old->product_type)))
795 return WIMLIB_ERR_NOMEM;
796 if (old->product_suite && !(new->product_suite = STRDUP(old->product_suite)))
797 return WIMLIB_ERR_NOMEM;
799 if (old->languages) {
800 new->languages = CALLOC(old->num_languages, sizeof(char*));
802 return WIMLIB_ERR_NOMEM;
803 new->num_languages = old->num_languages;
804 for (i = 0; i < new->num_languages; i++) {
805 if (!old->languages[i])
807 new->languages[i] = STRDUP(old->languages[i]);
808 if (!new->languages[i])
809 return WIMLIB_ERR_NOMEM;
812 if (old->default_language &&
813 !(new->default_language = STRDUP(old->default_language)))
814 return WIMLIB_ERR_NOMEM;
815 if (old->system_root && !(new->system_root = STRDUP(old->system_root)))
816 return WIMLIB_ERR_NOMEM;
820 static int clone_image_info(const struct image_info *old, struct image_info *new)
824 new->dir_count = old->dir_count;
825 new->file_count = old->file_count;
826 new->total_bytes = old->total_bytes;
827 new->hard_link_bytes = old->hard_link_bytes;
828 new->creation_time = old->creation_time;
829 new->last_modification_time = old->last_modification_time;
831 if (!(new->name = STRDUP(old->name)))
832 return WIMLIB_ERR_NOMEM;
834 if (old->description)
835 if (!(new->description = STRDUP(old->description)))
836 return WIMLIB_ERR_NOMEM;
838 if (old->display_name)
839 if (!(new->display_name = STRDUP(old->display_name)))
840 return WIMLIB_ERR_NOMEM;
842 if (old->display_description)
843 if (!(new->display_description = STRDUP(old->display_description)))
844 return WIMLIB_ERR_NOMEM;
847 if (!(new->flags = STRDUP(old->flags)))
848 return WIMLIB_ERR_NOMEM;
850 if (old->windows_info_exists) {
851 new->windows_info_exists = true;
852 return clone_windows_info(&old->windows_info,
858 /* Copies the XML information for an image between WIM files.
860 * @dest_image_name and @dest_image_description are ignored if they are NULL;
861 * otherwise, they are used to override the image name and/or image description
862 * from the XML data in the source WIM file. */
863 int xml_export_image(const struct wim_info *old_wim_info,
865 struct wim_info **new_wim_info_p,
866 const char *dest_image_name,
867 const char *dest_image_description)
869 struct wim_info *new_wim_info;
870 struct image_info *image_info;
875 DEBUG("Copying XML data between WIM files for source image %d.", image);
877 wimlib_assert(image >= 1 && image <= old_wim_info->num_images);
880 if (*new_wim_info_p) {
881 new_wim_info = *new_wim_info_p;
883 new_wim_info = CALLOC(1, sizeof(struct wim_info));
888 image_info = add_image_info_struct(new_wim_info);
892 ret = clone_image_info(&old_wim_info->images[image - 1], image_info);
896 image_info->index = new_wim_info->num_images;
898 if (dest_image_name) {
899 FREE(image_info->name);
900 image_info->name = STRDUP(dest_image_name);
901 if (!image_info->name)
904 if (dest_image_description) {
905 FREE(image_info->description);
906 image_info->description = STRDUP(dest_image_description);
907 if (!image_info->description)
910 *new_wim_info_p = new_wim_info;
913 ERROR("Out of memory");
914 free_wim_info(new_wim_info);
915 return WIMLIB_ERR_NOMEM;
918 /* Removes an image from the XML information. */
919 void xml_delete_image(struct wim_info **wim_info_p, int image)
921 struct wim_info *wim_info;
924 DEBUG("Deleting image %d from the XML data.", image);
926 wim_info = *wim_info_p;
928 wimlib_assert(wim_info);
929 wimlib_assert(image >= 1 && image <= wim_info->num_images);
931 destroy_image_info(&wim_info->images[image - 1]);
933 for (i = image - 1; i < wim_info->num_images - 1; i++) {
934 memcpy(&wim_info->images[i], &wim_info->images[i + 1],
935 sizeof(struct image_info));
936 wim_info->images[i].index--;
939 if (--wim_info->num_images == 0) {
940 free_wim_info(wim_info);
945 size_t xml_get_max_image_name_len(const WIMStruct *w)
949 uint num_images = w->wim_info->num_images;
950 for (i = 0; i < num_images; i++)
951 len = max(len, strlen(w->wim_info->images[i].name));
955 #ifdef ENABLE_CUSTOM_MEMORY_ALLOCATOR
956 void xml_set_memory_allocator(void *(*malloc_func)(size_t),
957 void (*free_func)(void *),
958 void *(*realloc_func)(void *, size_t))
960 xmlMemSetup(free_func, malloc_func, realloc_func, STRDUP);
964 void xml_update_image_info(WIMStruct *w, int image)
966 struct image_info *image_info;
969 DEBUG("Updating the image info for image %d", image);
971 image_info = &w->wim_info->images[image - 1];
972 root = w->image_metadata[image - 1].root_dentry;
974 calculate_dir_tree_statistics(root, w->lookup_table,
975 &image_info->dir_count,
976 &image_info->file_count,
977 &image_info->total_bytes,
978 &image_info->hard_link_bytes);
980 image_info->last_modification_time = get_wim_timestamp();
983 /* Adds an image to the XML information. */
984 int xml_add_image(WIMStruct *w, struct dentry *root_dentry, const char *name,
985 const char *description, const char *flags_element)
987 struct wim_info *wim_info;
988 struct image_info *image_info;
992 DEBUG("Adding image: name = %s, description = %s, flags_element = %s",
993 name, description, flags_element);
995 /* If this is the first image, allocate the struct wim_info. Otherwise
996 * use the existing struct wim_info. */
998 wim_info = w->wim_info;
1000 DEBUG("Allocing struct wim_info with 1 image");
1001 wim_info = CALLOC(1, sizeof(struct wim_info));
1003 ERROR("Could not allocate WIM information struct--- "
1005 return WIMLIB_ERR_NOMEM;
1009 image_info = add_image_info_struct(wim_info);
1011 goto out_free_wim_info;
1013 if (!(image_info->name = STRDUP(name)))
1014 goto out_destroy_image_info;
1016 if (description && !(image_info->description = STRDUP(description)))
1017 goto out_destroy_image_info;
1018 if (flags_element && !(image_info->flags = STRDUP(flags_element)))
1019 goto out_destroy_image_info;
1021 w->wim_info = wim_info;
1022 image_info->index = wim_info->num_images;
1023 image_info->creation_time = get_wim_timestamp();
1024 xml_update_image_info(w, image_info->index);
1027 out_destroy_image_info:
1028 destroy_image_info(image_info);
1031 wim_info->num_images--;
1034 ERROR("Out of memory");
1035 return WIMLIB_ERR_NOMEM;
1038 /* Prints information about the specified image from struct wim_info structure.
1039 * @image may be WIM_ALL_IMAGES. */
1040 void print_image_info(const struct wim_info *wim_info, int image)
1043 const struct image_info *image_info;
1049 if (image == WIM_ALL_IMAGES) {
1050 for (i = 1; i <= wim_info->num_images; i++)
1051 print_image_info(wim_info, i);
1053 image_info = &wim_info->images[image - 1];
1055 printf("Index: %"PRIu64"\n",
1057 printf("Name: %s\n",
1060 /* Always print the Description: part even if there is no
1062 if (image_info->description)
1063 desc = image_info->description;
1066 printf("Description: %s\n", desc);
1068 if (image_info->display_name)
1069 printf("Display Name: %s\n",
1070 image_info->display_name);
1072 if (image_info->display_description)
1073 printf("Display Description: %s\n",
1074 image_info->display_description);
1076 printf("Directory Count: %"PRIu64"\n",
1077 image_info->dir_count);
1078 printf("File Count: %"PRIu64"\n",
1079 image_info->file_count);
1080 printf("Total Bytes: %"PRIu64"\n",
1081 image_info->total_bytes);
1082 printf("Hard Link Bytes: %"PRIu64"\n",
1083 image_info->hard_link_bytes);
1085 ctime = wim_timestamp_to_unix(image_info->creation_time);
1086 mtime = wim_timestamp_to_unix(image_info->last_modification_time);
1088 printf("Creation Time: %s", asctime(localtime(&ctime)));
1089 printf("Last Modification Time: %s", asctime(localtime(&mtime)));
1090 if (image_info->windows_info_exists)
1091 print_windows_info(&image_info->windows_info);
1092 if (image_info->flags)
1093 printf("Flags: %s\n", image_info->flags);
1099 * Reads the XML data from a WIM file.
1101 int read_xml_data(FILE *fp, const struct resource_entry *res, u8 **xml_data_ret,
1102 struct wim_info **info_ret)
1109 DEBUG("XML data is %"PRIu64" bytes at offset %"PRIu64"",
1110 (u64)res->size, res->offset);
1112 if (resource_is_compressed(res)) {
1113 ERROR("XML data is supposed to be uncompressed");
1114 ret = WIMLIB_ERR_XML;
1115 goto out_cleanup_parser;
1117 if (res->size < 2) {
1118 ERROR("XML data must be at least 2 bytes");
1119 ret = WIMLIB_ERR_XML;
1120 goto out_cleanup_parser;
1123 xml_data = MALLOC(res->size + 2);
1125 ret = WIMLIB_ERR_NOMEM;
1126 goto out_cleanup_parser;
1128 ret = read_uncompressed_resource(fp, res->offset, res->size, xml_data);
1130 goto out_free_xml_data;
1132 xml_data[res->size] = 0;
1133 xml_data[res->size + 1] = 0;
1135 DEBUG("Parsing XML using libxml2 to create XML tree.");
1137 doc = xmlReadMemory(xml_data, res->size, "noname.xml", "UTF-16", 0);
1141 ERROR("Failed to parse XML data");
1142 ret = WIMLIB_ERR_XML;
1143 goto out_free_xml_data;
1146 DEBUG("Constructing WIM information structure from XML tree.");
1148 root = xmlDocGetRootElement(doc);
1150 ERROR("Empty XML document");
1151 ret = WIMLIB_ERR_XML;
1155 if (!node_is_element(root) || !node_name_is(root, "WIM")) {
1156 ERROR("Expected <WIM> for the root XML element (found <%s>)",
1158 ret = WIMLIB_ERR_XML;
1162 ret = xml_read_wim_info(root, info_ret);
1166 DEBUG("Freeing XML tree.");
1170 *xml_data_ret = xml_data;
1181 #define CHECK_RET ({ if (ret < 0) { \
1182 ERROR("Error writing XML data"); \
1183 ret = WIMLIB_ERR_WRITE; \
1188 * Writes XML data to a WIM file.
1190 * If @total_bytes is non-zero, it specifies what to write to the TOTALBYTES
1191 * element in the XML data. If zero, TOTALBYTES is given the default value of
1192 * the offset of the XML data.
1194 int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
1198 xmlTextWriter *writer;
1203 const xmlChar *content;
1206 size_t bytes_written;
1208 wimlib_assert(image == WIM_ALL_IMAGES ||
1209 (wim_info != NULL && image >= 1 &&
1210 image <= wim_info->num_images));
1212 /* The contents of the <TOTALBYTES> element in the XML data, under the
1213 * <WIM> element not the <IMAGE> element, is (for non-spit WIMs) the
1214 * size of the WIM file excluding the XML data and integrity table,
1215 * which is the current offset, since the XML data goes at the end of
1216 * the WIM file before the integrity table. */
1217 if (total_bytes == 0) {
1218 total_bytes = ftello(out);
1219 if (total_bytes == (u64)-1)
1220 return WIMLIB_ERR_WRITE;
1223 DEBUG("Creating XML buffer and text writer.");
1224 buf = xmlBufferCreate();
1226 ERROR("Failed to allocate XML buffer");
1227 ret = WIMLIB_ERR_NOMEM;
1230 writer = xmlNewTextWriterMemory(buf, 0);
1232 ERROR("Failed to allocate XML writer");
1233 ret = WIMLIB_ERR_NOMEM;
1238 /* M$'s WIM files do not have XML declarations, so do not write one.
1239 * I'm not sure how we can force the document to be written in UTF-16
1240 * without calling xmlTextWriterStartDocument(), though, so currently it
1241 * is composed in a buffer UTF-8, then converted to UTF-16. */
1243 ret = xmlTextWriterStartDocument(writer, NULL, "UTF-16", NULL);
1247 DEBUG("Writing <WIM> element");
1248 ret = xmlTextWriterStartElement(writer, "WIM");
1251 ret = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
1256 num_images = wim_info->num_images;
1259 DEBUG("Writing %u <IMAGE> elements", num_images);
1261 for (i = 1; i <= num_images; i++) {
1262 if (image != WIM_ALL_IMAGES && i != image)
1264 DEBUG("Writing <IMAGE> element for image %d", i);
1265 ret = xml_write_image_info(writer, &wim_info->images[i - 1]);
1269 ret = xmlTextWriterEndElement(writer);
1272 ret = xmlTextWriterEndDocument(writer);
1275 DEBUG("Done composing XML document. Now converting to UTF-16 and "
1276 "writing it to the output file.");
1278 content = xmlBufferContent(buf);
1279 len = xmlBufferLength(buf);
1281 utf16_str = utf8_to_utf16(content, len, &utf16_len);
1283 ret = WIMLIB_ERR_NOMEM;
1287 if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF) ||
1288 ((bytes_written = fwrite(utf16_str, 1, utf16_len, out))
1290 ERROR_WITH_ERRNO("Error writing XML data");
1291 ret = WIMLIB_ERR_WRITE;
1295 DEBUG("Cleaning up.");
1301 xmlFreeTextWriter(writer);
1308 /* Returns the name of the specified image. */
1309 WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image)
1311 DEBUG("Getting the name of image %d", image);
1312 if (image < 1 || image > w->hdr.image_count)
1315 return w->wim_info->images[image - 1].name;
1318 /* Returns the description of the specified image. */
1319 WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w,
1322 DEBUG("Getting the description of image %d", image);
1323 if (image < 1 || image > w->hdr.image_count)
1326 return w->wim_info->images[image - 1].description;
1329 /* Determines if an image name is already used by some image in the WIM. */
1330 WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name)
1334 DEBUG("Checking to see if the image name `%s' is already in use", name);
1335 if (!name || !w->wim_info)
1337 for (i = 1; i <= w->wim_info->num_images; i++)
1338 if (strcmp(w->wim_info->images[i - 1].name, name) == 0)
1344 WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp)
1346 DEBUG("Extracting the XML data.");
1347 if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) !=
1348 w->hdr.xml_res_entry.size) {
1349 ERROR_WITH_ERRNO("Failed to extract XML data");
1350 return WIMLIB_ERR_WRITE;
1355 /* Sets the name of an image in the WIM. */
1356 WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name)
1361 DEBUG("Setting the name of image %d to %s", image, name);
1363 if (!name || !*name) {
1364 ERROR("Must specify a non-empty string for the image name");
1365 return WIMLIB_ERR_INVALID_PARAM;
1367 if (image < 1 || image > w->hdr.image_count) {
1368 ERROR("%d is not a valid image", image);
1369 return WIMLIB_ERR_INVALID_IMAGE;
1372 for (i = 1; i <= w->hdr.image_count; i++) {
1375 if (strcmp(w->wim_info->images[i - 1].name, name) == 0) {
1376 ERROR("The name `%s' is already used for image %d",
1378 return WIMLIB_ERR_IMAGE_NAME_COLLISION;
1384 ERROR("Out of memory");
1385 return WIMLIB_ERR_NOMEM;
1387 FREE(w->wim_info->images[image - 1].name);
1388 w->wim_info->images[image - 1].name = p;
1392 /* Sets the description of an image in the WIM. */
1393 WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image,
1394 const char *description)
1398 DEBUG("Setting the description of image %d to %s", image, description);
1400 if (image < 1 || image > w->hdr.image_count) {
1401 ERROR("%d is not a valid image", image);
1402 return WIMLIB_ERR_INVALID_IMAGE;
1405 p = STRDUP(description);
1407 ERROR("Out of memory");
1408 return WIMLIB_ERR_NOMEM;
1413 FREE(w->wim_info->images[image - 1].description);
1414 w->wim_info->images[image - 1].description = p;