4 * Deals with the XML information in WIM files. Uses the C library libxml2.
6 * Copyright (C) 2012 Eric Biggers
8 * wimlib - Library for working with WIM files
10 * This library is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 2.1 of the License, or (at your option) any
15 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
17 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License along
20 * with this library; if not, write to the Free Software Foundation, Inc., 59
21 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wimlib_internal.h"
27 #include "timestamp.h"
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #include <libxml/xmlwriter.h>
34 /* The following 4 structures are used to form an in-memory representation of
35 * the XML data (other than the raw parse tree from libxml). */
37 struct windows_version {
49 char *installation_type;
54 char *default_language;
57 bool windows_version_exists;
58 struct windows_version windows_version;
68 u64 last_modification_time;
69 bool windows_info_exists;
70 struct windows_info windows_info;
74 char *display_description;
79 /* Returns a statically allocated string that is a string representation of the
80 * architecture number. */
81 static const char *get_arch(int arch)
91 /* XXX Are there other arch values? */
93 snprintf(buf, sizeof(buf), "%d (unknown)", arch);
99 /* Iterate through the children of an xmlNode. */
100 #define for_node_child(parent, child) for (child = parent->children; \
101 child != NULL; child = child->next)
103 /* Utility functions for xmlNodes */
104 static inline bool node_is_element(xmlNode *node)
106 return node->type == XML_ELEMENT_NODE;
109 static inline bool node_is_text(xmlNode *node)
111 return node->type == XML_TEXT_NODE;
114 static inline bool node_is_attribute(xmlNode *node)
116 return node->type == XML_ATTRIBUTE_NODE;
119 static inline bool node_name_is(xmlNode *node, const char *name)
121 /* For now, both upper case and lower case element names are accepted. */
122 return strcasecmp((const char *)node->name, name) == 0;
125 /* Finds the text node that is a child of an element node and returns its
126 * content converted to a 64-bit unsigned integer. Returns 0 if no text node is
128 static u64 node_get_u64(const xmlNode *u64_node)
131 for_node_child(u64_node, child)
132 if (node_is_text(child))
133 return strtoull((const char *)child->content, NULL, 10);
137 /* Like node_get_u64(), but expects a number in base 16. */
138 static u64 node_get_hex_u64(const xmlNode *u64_node)
141 for_node_child(u64_node, child)
142 if (node_is_text(child))
143 return strtoull(child->content, NULL, 16);
147 static int node_get_string(const xmlNode *string_node, char **str)
152 for_node_child(string_node, child) {
153 if (node_is_text(child) && child->content) {
154 p = STRDUP(child->content);
156 return WIMLIB_ERR_NOMEM;
164 /* Returns the timestamp from a time node. It has child elements <HIGHPART> and
165 * <LOWPART> that are then used to construct a 64-bit timestamp. */
166 static u64 node_get_timestamp(const xmlNode *time_node)
171 for_node_child(time_node, child) {
172 if (!node_is_element(child))
174 if (node_name_is(child, "HIGHPART"))
175 high_part = node_get_hex_u64(child);
176 else if (node_name_is(child, "LOWPART"))
177 low_part = node_get_hex_u64(child);
179 return (u64)low_part | ((u64)high_part << 32);
182 /* Used to sort an array of struct image_infos by their image indices. */
183 static int sort_by_index(const void *p1, const void *p2)
185 u64 index_1 = ((struct image_info*)p1)->index;
186 u64 index_2 = ((struct image_info*)p1)->index;
187 if (index_1 < index_2)
189 else if (index_1 > index_2)
196 /* Frees memory allocated inside a struct windows_info structure. */
197 static void destroy_windows_info(struct windows_info *windows_info)
201 FREE(windows_info->product_name);
202 FREE(windows_info->edition_id);
203 FREE(windows_info->installation_type);
204 FREE(windows_info->product_type);
205 for (i = 0; i < windows_info->num_languages; i++)
206 FREE(windows_info->languages[i]);
207 FREE(windows_info->languages);
208 FREE(windows_info->system_root);
211 /* Frees memory allocated inside a struct image_info structure. */
212 static void destroy_image_info(struct image_info *image_info)
214 FREE(image_info->name);
215 FREE(image_info->description);
216 FREE(image_info->flags);
217 FREE(image_info->display_name);
218 FREE(image_info->display_description);
219 destroy_windows_info(&image_info->windows_info);
220 memset(image_info, 0, sizeof(struct image_info));
223 void free_wim_info(struct wim_info *info)
228 for (i = 0; i < info->num_images; i++)
229 destroy_image_info(&info->images[i]);
236 /* Reads the information from a <VERSION> element inside the <WINDOWS> element.
238 static void xml_read_windows_version(const xmlNode *version_node,
239 struct windows_version* windows_version)
242 for_node_child(version_node, child) {
243 if (!node_is_element(child))
245 if (node_name_is(child, "MAJOR"))
246 windows_version->major = node_get_u64(child);
247 else if (node_name_is(child, "MINOR"))
248 windows_version->minor = node_get_u64(child);
249 else if (node_name_is(child, "BUILD"))
250 windows_version->build = node_get_u64(child);
251 else if (node_name_is(child, "SPBUILD"))
252 windows_version->sp_build = node_get_u64(child);
253 else if (node_name_is(child, "SPLEVEL"))
254 windows_version->sp_level = node_get_u64(child);
258 /* Reads the information from a <LANGUAGE> element inside a <WINDOWS> element.
260 static int xml_read_languages(const xmlNode *languages_node,
261 char ***languages_ret,
262 u64 *num_languages_ret,
263 char **default_language_ret)
272 for_node_child(languages_node, child)
273 if (node_is_element(child) && node_name_is(child, "LANGUAGE"))
276 languages = CALLOC(num_languages, sizeof(char*));
278 return WIMLIB_ERR_NOMEM;
280 *languages_ret = languages;
281 *num_languages_ret = num_languages;
285 for_node_child(languages_node, child) {
286 if (!node_is_element(child))
288 if (node_name_is(child, "LANGUAGE"))
289 ret = node_get_string(child, &languages[i++]);
290 else if (node_name_is(child, "DEFAULT"))
291 ret = node_get_string(child, default_language_ret);
298 /* Reads the information from a <WINDOWS> element inside an <IMAGE> element. */
299 static int xml_read_windows_info(const xmlNode *windows_node,
300 struct windows_info *windows_info)
305 for_node_child(windows_node, child) {
306 if (!node_is_element(child))
308 if (node_name_is(child, "ARCH")) {
309 windows_info->arch = node_get_u64(child);
310 } else if (node_name_is(child, "PRODUCTNAME")) {
311 ret = node_get_string(child,
312 &windows_info->product_name);
313 } else if (node_name_is(child, "EDITIONID")) {
314 ret = node_get_string(child,
315 &windows_info->edition_id);
316 } else if (node_name_is(child, "INSTALLATIONTYPE")) {
317 ret = node_get_string(child,
318 &windows_info->installation_type);
319 } else if (node_name_is(child, "PRODUCTTYPE")) {
320 ret = node_get_string(child,
321 &windows_info->product_type);
322 } else if (node_name_is(child, "PRODUCTSUITE")) {
323 ret = node_get_string(child,
324 &windows_info->product_suite);
325 } else if (node_name_is(child, "LANGUAGES")) {
326 ret = xml_read_languages(child,
327 &windows_info->languages,
328 &windows_info->num_languages,
329 &windows_info->default_language);
330 } else if (node_name_is(child, "VERSION")) {
331 xml_read_windows_version(child,
332 &windows_info->windows_version);
333 windows_info->windows_version_exists = true;
334 } else if (node_name_is(child, "SYSTEMROOT")) {
335 ret = node_get_string(child, &windows_info->system_root);
336 } else if (node_name_is(child, "HAL")) {
337 ret = node_get_string(child, &windows_info->hal);
346 /* Reads the information from an <IMAGE> element. */
347 static int xml_read_image_info(xmlNode *image_node,
348 struct image_info *image_info)
354 index_prop = xmlGetProp(image_node, "INDEX");
356 image_info->index = strtoul(index_prop, NULL, 10);
359 image_info->index = 0;
363 for_node_child(image_node, child) {
364 if (!node_is_element(child))
366 if (node_name_is(child, "DIRCOUNT"))
367 image_info->dir_count = node_get_u64(child);
368 else if (node_name_is(child, "FILECOUNT"))
369 image_info->file_count = node_get_u64(child);
370 else if (node_name_is(child, "TOTALBYTES"))
371 image_info->total_bytes = node_get_u64(child);
372 else if (node_name_is(child, "HARDLINKBYTES"))
373 image_info->hard_link_bytes = node_get_u64(child);
374 else if (node_name_is(child, "CREATIONTIME"))
375 image_info->creation_time = node_get_timestamp(child);
376 else if (node_name_is(child, "LASTMODIFICATIONTIME"))
377 image_info->last_modification_time = node_get_timestamp(child);
378 else if (node_name_is(child, "WINDOWS")) {
379 DEBUG("Found <WINDOWS> tag\n");
380 ret = xml_read_windows_info(child,
381 &image_info->windows_info);
382 image_info->windows_info_exists = true;
383 } else if (node_name_is(child, "NAME")) {
384 ret = node_get_string(child, &image_info->name);
385 } else if (node_name_is(child, "DESCRIPTION")) {
386 ret = node_get_string(child, &image_info->description);
387 } else if (node_name_is(child, "FLAGS")) {
388 ret = node_get_string(child, &image_info->flags);
389 } else if (node_name_is(child, "DISPLAYNAME")) {
390 ret = node_get_string(child, &image_info->display_name);
391 } else if (node_name_is(child, "DISPLAYDESCRIPTION")) {
392 ret = node_get_string(child, &image_info->display_description);
397 if (!image_info->name) {
398 WARNING("Image with index %"PRIu64" has no name\n",
400 image_info->name = MALLOC(1);
401 if (!image_info->name) {
402 ERROR("Out of memory!\n");
403 return WIMLIB_ERR_NOMEM;
405 image_info->name[0] = '\0';
412 /* Reads the information from a <WIM> element, which should be the root element
413 * of the XML tree. */
414 static int xml_read_wim_info(const xmlNode *wim_node, struct wim_info **wim_info_ret)
416 struct wim_info *wim_info;
420 struct image_info *cur_image_info;
422 wim_info = CALLOC(1, sizeof(struct wim_info));
424 ERROR("Out of memory!\n");
425 return WIMLIB_ERR_NOMEM;
428 /* Count how many images there are. */
430 for_node_child(wim_node, child)
431 if (node_is_element(child) && node_name_is(child, "IMAGE"))
437 /* Allocate the array of struct image_infos and fill them in. */
438 wim_info->images = CALLOC(num_images, sizeof(wim_info->images[0]));
439 if (!wim_info->images) {
440 ret = WIMLIB_ERR_NOMEM;
441 ERROR("Out of memory!\n");
444 wim_info->num_images = num_images;
445 cur_image_info = wim_info->images;
446 for_node_child(wim_node, child) {
447 if (!node_is_element(child))
449 if (node_name_is(child, "IMAGE")) {
450 DEBUG("Found <IMAGE> tag\n");
451 ret = xml_read_image_info(child, cur_image_info++);
454 } else if (node_name_is(child, "TOTALBYTES")) {
455 wim_info->total_bytes = node_get_u64(child);
459 /* Sort the array of struct image_infos by image index. */
460 qsort(wim_info->images, wim_info->num_images,
461 sizeof(struct image_info), sort_by_index);
463 *wim_info_ret = wim_info;
466 free_wim_info(wim_info);
470 /* Prints the information contained in a struct windows_info structure. */
471 static void print_windows_info(const struct windows_info *windows_info)
474 const struct windows_version *windows_version;
476 printf("Architecture: %s\n", get_arch(windows_info->arch));
477 printf("Product Name: %s\n", windows_info->product_name);
478 printf("Edition ID: %s\n", windows_info->edition_id);
479 printf("Installation Type: %s\n", windows_info->installation_type);
480 if (windows_info->hal)
481 printf("HAL: %s\n", windows_info->hal);
482 printf("Product Type: %s\n", windows_info->product_type);
483 if (windows_info->product_suite)
484 printf("Product Suite: %s\n", windows_info->product_suite);
485 printf("Languages: ");
486 for (i = 0; i < windows_info->num_languages; i++) {
487 fputs(windows_info->languages[i], stdout);
491 printf("Default Language: %s\n", windows_info->default_language);
492 printf("System Root: %s\n", windows_info->system_root);
493 if (windows_info->windows_version_exists) {
494 windows_version = &windows_info->windows_version;
495 printf("Major Version: %"PRIu64"\n",
496 windows_version->major);
497 printf("Minor Version: %"PRIu64"\n",
498 windows_version->minor);
499 printf("Build: %"PRIu64"\n",
500 windows_version->build);
501 printf("Service Pack Build: %"PRIu64"\n",
502 windows_version->sp_build);
503 printf("Service Pack Level: %"PRIu64"\n",
504 windows_version->sp_level);
509 /* Writes the information contained in a struct windows_version structure to the XML
510 * document being constructed in memory. This is the <VERSION> element inside
511 * the <WINDOWS> element. */
512 static int xml_write_windows_version(xmlTextWriter *writer,
513 const struct windows_version *version)
516 rc = xmlTextWriterStartElement(writer, "VERSION");
520 rc = xmlTextWriterWriteFormatElement(writer, "MAJOR", "%"PRIu64,
525 rc = xmlTextWriterWriteFormatElement(writer, "MINOR", "%"PRIu64,
530 rc = xmlTextWriterWriteFormatElement(writer, "BUILD", "%"PRIu64,
535 rc = xmlTextWriterWriteFormatElement(writer, "SPBUILD", "%"PRIu64,
540 rc = xmlTextWriterWriteFormatElement(writer, "SPLEVEL", "%"PRIu64,
545 return xmlTextWriterEndElement(writer); /* </VERSION> */
548 /* Writes the information contained in a struct windows_info structure to the XML
549 * document being constructed in memory. This is the <WINDOWS> element. */
550 static int xml_write_windows_info(xmlTextWriter *writer,
551 const struct windows_info *windows_info)
554 rc = xmlTextWriterStartElement(writer, "WINDOWS");
559 rc = xmlTextWriterWriteFormatElement(writer, "ARCH", "%"PRIu64,
564 if (windows_info->product_name) {
565 rc = xmlTextWriterWriteElement(writer, "PRODUCTNAME",
566 windows_info->product_name);
571 if (windows_info->edition_id) {
572 rc = xmlTextWriterWriteElement(writer, "EDITIONID",
573 windows_info->edition_id);
578 if (windows_info->installation_type) {
579 rc = xmlTextWriterWriteElement(writer, "INSTALLATIONTYPE",
580 windows_info->installation_type);
585 if (windows_info->hal) {
586 rc = xmlTextWriterWriteElement(writer, "HAL",
592 if (windows_info->system_root) {
593 rc = xmlTextWriterWriteElement(writer, "SYSTEMROOT",
594 windows_info->system_root);
599 if (windows_info->product_type) {
600 rc = xmlTextWriterWriteElement(writer, "PRODUCTTYPE",
601 windows_info->product_type);
606 if (windows_info->product_suite) {
607 rc = xmlTextWriterWriteElement(writer, "PRODUCTSUITE",
608 windows_info->product_suite);
613 if (windows_info->num_languages) {
614 rc = xmlTextWriterStartElement(writer, "LANGUAGES");
618 for (int i = 0; i < windows_info->num_languages; i++) {
619 rc = xmlTextWriterWriteElement(writer, "LANGUAGE",
620 windows_info->languages[i]);
624 rc = xmlTextWriterWriteElement(writer, "DEFAULT",
625 windows_info->default_language);
629 rc = xmlTextWriterEndElement(writer); /* </LANGUAGES> */
634 if (windows_info->windows_version_exists) {
635 rc = xml_write_windows_version(writer, &windows_info->windows_version);
640 return xmlTextWriterEndElement(writer); /* </WINDOWS> */
643 /* Writes a time element to the XML document being constructed in memory. */
644 static int xml_write_time(xmlTextWriter *writer, const char *element_name,
648 rc = xmlTextWriterStartElement(writer, element_name);
652 rc = xmlTextWriterWriteFormatElement(writer, "HIGHPART",
653 "0x%"PRIX32, (u32)(time >> 32));
657 rc = xmlTextWriterWriteFormatElement(writer, "LOWPART",
658 "0x%"PRIX32, (u32)time);
662 rc = xmlTextWriterEndElement(writer); /* </@element_name> */
669 /* Writes an <IMAGE> element to the XML document. */
670 static int xml_write_image_info(xmlTextWriter *writer,
671 const struct image_info *image_info)
674 rc = xmlTextWriterStartElement(writer, "IMAGE");
678 rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%"PRIu64,
683 rc = xmlTextWriterWriteFormatElement(writer, "DIRCOUNT", "%"PRIu64,
684 image_info->dir_count);
688 rc = xmlTextWriterWriteFormatElement(writer, "FILECOUNT", "%"PRIu64,
689 image_info->file_count);
693 rc = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
694 image_info->total_bytes);
698 rc = xmlTextWriterWriteFormatElement(writer, "HARDLINKBYTES", "%"PRIu64,
699 image_info->hard_link_bytes);
703 rc = xml_write_time(writer, "CREATIONTIME",
704 image_info->creation_time);
708 rc = xml_write_time(writer, "LASTMODIFICATIONTIME",
709 image_info->last_modification_time);
713 if (image_info->windows_info_exists) {
714 rc = xml_write_windows_info(writer, &image_info->windows_info);
718 DEBUG("<WINDOWS> tag does not exist.\n");
721 if (image_info->name) {
722 rc = xmlTextWriterWriteElement(writer, "NAME", image_info->name);
726 if (image_info->description) {
727 rc = xmlTextWriterWriteElement(writer, "DESCRIPTION",
728 image_info->description);
732 if (image_info->display_name) {
733 rc = xmlTextWriterWriteElement(writer, "DISPLAYNAME",
734 image_info->display_name);
738 if (image_info->display_description) {
739 rc = xmlTextWriterWriteElement(writer, "DISPLAYDESCRIPTION",
740 image_info->display_description);
745 if (image_info->flags) {
746 rc = xmlTextWriterWriteElement(writer, "FLAGS",
752 return xmlTextWriterEndElement(writer); /* </IMAGE> */
757 /* Makes space for another image in the XML information and return a pointer to
759 static struct image_info *add_image_info_struct(struct wim_info *wim_info)
761 struct image_info *images;
763 images = CALLOC(wim_info->num_images + 1, sizeof(struct image_info));
766 memcpy(images, wim_info->images,
767 wim_info->num_images * sizeof(struct image_info));
768 FREE(wim_info->images);
769 wim_info->images = images;
770 wim_info->num_images++;
771 return &images[wim_info->num_images - 1];
774 static int clone_windows_info(const struct windows_info *old,
775 struct windows_info *new)
779 if (old->product_name && !(new->product_name = STRDUP(old->product_name)))
780 return WIMLIB_ERR_NOMEM;
781 if (old->edition_id && !(new->edition_id = STRDUP(old->edition_id)))
782 return WIMLIB_ERR_NOMEM;
783 if (old->installation_type && !(new->installation_type =
784 STRDUP(old->installation_type)))
785 return WIMLIB_ERR_NOMEM;
786 if (old->hal && !(new->hal = STRDUP(old->hal)))
787 return WIMLIB_ERR_NOMEM;
788 if (old->product_type && !(new->product_type = STRDUP(old->product_type)))
789 return WIMLIB_ERR_NOMEM;
790 if (old->product_suite && !(new->product_suite = STRDUP(old->product_suite)))
791 return WIMLIB_ERR_NOMEM;
793 if (old->languages) {
794 new->languages = CALLOC(old->num_languages, sizeof(char*));
796 return WIMLIB_ERR_NOMEM;
797 new->num_languages = old->num_languages;
798 for (i = 0; i < new->num_languages; i++) {
799 if (!old->languages[i])
801 new->languages[i] = STRDUP(old->languages[i]);
802 if (!new->languages[i])
803 return WIMLIB_ERR_NOMEM;
806 if (old->default_language &&
807 !(new->default_language = STRDUP(old->default_language)))
808 return WIMLIB_ERR_NOMEM;
809 if (old->system_root && !(new->system_root = STRDUP(old->system_root)))
810 return WIMLIB_ERR_NOMEM;
814 static int clone_image_info(const struct image_info *old, struct image_info *new)
818 new->dir_count = old->dir_count;
819 new->file_count = old->file_count;
820 new->total_bytes = old->total_bytes;
821 new->hard_link_bytes = old->hard_link_bytes;
822 new->creation_time = old->creation_time;
823 new->last_modification_time = old->last_modification_time;
825 if (!(new->name = STRDUP(old->name)))
826 return WIMLIB_ERR_NOMEM;
828 if (old->description)
829 if (!(new->description = STRDUP(old->description)))
830 return WIMLIB_ERR_NOMEM;
832 if (old->display_name)
833 if (!(new->display_name = STRDUP(old->display_name)))
834 return WIMLIB_ERR_NOMEM;
836 if (old->display_description)
837 if (!(new->display_description = STRDUP(old->display_description)))
838 return WIMLIB_ERR_NOMEM;
841 if (!(new->flags = STRDUP(old->flags)))
842 return WIMLIB_ERR_NOMEM;
844 if (old->windows_info_exists) {
845 new->windows_info_exists = true;
846 return clone_windows_info(&old->windows_info,
852 /* Copies the XML information for an image between WIM files.
854 * @dest_image_name and @dest_image_description are ignored if they are NULL;
855 * otherwise, they are used to override the image name and/or image description
856 * from the XML data in the source WIM file. */
857 int xml_export_image(const struct wim_info *old_wim_info,
859 struct wim_info **new_wim_info_p,
860 const char *dest_image_name,
861 const char *dest_image_description)
863 struct wim_info *new_wim_info;
864 struct image_info *image_info;
869 DEBUG("Copying XML data between WIM files for source image %d\n",
872 wimlib_assert(image >= 1 && image <= old_wim_info->num_images);
875 if (*new_wim_info_p) {
876 new_wim_info = *new_wim_info_p;
878 new_wim_info = CALLOC(1, sizeof(struct wim_info));
883 image_info = add_image_info_struct(new_wim_info);
887 ret = clone_image_info(&old_wim_info->images[image - 1], image_info);
891 image_info->index = new_wim_info->num_images;
893 if (dest_image_name) {
894 FREE(image_info->name);
895 image_info->name = STRDUP(dest_image_name);
896 if (!image_info->name)
899 if (dest_image_description) {
900 FREE(image_info->description);
901 image_info->description = STRDUP(dest_image_description);
902 if (!image_info->description)
905 *new_wim_info_p = new_wim_info;
908 ERROR("Out of memory!\n");
909 free_wim_info(new_wim_info);
910 return WIMLIB_ERR_NOMEM;
913 /* Removes an image from the XML information. */
914 void xml_delete_image(struct wim_info **wim_info_p, int image)
916 struct wim_info *wim_info;
919 DEBUG("Deleting image %d from the XML data\n", image);
921 wim_info = *wim_info_p;
923 wimlib_assert(wim_info);
924 wimlib_assert(image >= 1 && image <= wim_info->num_images);
926 destroy_image_info(&wim_info->images[image - 1]);
928 for (i = image - 1; i < wim_info->num_images - 1; i++) {
929 memcpy(&wim_info->images[i], &wim_info->images[i + 1],
930 sizeof(struct image_info));
931 wim_info->images[i].index--;
934 if (--wim_info->num_images == 0) {
935 free_wim_info(wim_info);
940 size_t xml_get_max_image_name_len(const WIMStruct *w)
944 uint num_images = w->wim_info->num_images;
945 for (i = 0; i < num_images; i++)
946 len = max(len, strlen(w->wim_info->images[i].name));
950 #ifdef ENABLE_CUSTOM_MEMORY_ALLOCATOR
951 void xml_set_memory_allocator(void *(*malloc_func)(size_t),
952 void (*free_func)(void *),
953 void *(*realloc_func)(void *, size_t))
955 xmlMemSetup(free_func, malloc_func, realloc_func, STRDUP);
959 void xml_update_image_info(WIMStruct *w, int image)
961 struct image_info *image_info;
964 DEBUG("Updating the image info for image %d\n", image);
966 image_info = &w->wim_info->images[image - 1];
967 root = w->image_metadata[image - 1].root_dentry;
969 calculate_dir_tree_statistics(root, w->lookup_table,
970 &image_info->dir_count,
971 &image_info->file_count,
972 &image_info->total_bytes,
973 &image_info->hard_link_bytes);
975 image_info->last_modification_time = get_timestamp();
978 /* Adds an image to the XML information. */
979 int xml_add_image(WIMStruct *w, struct dentry *root_dentry, const char *name,
980 const char *description, const char *flags_element)
982 struct wim_info *wim_info;
983 struct image_info *image_info;
987 DEBUG("Adding image: name = %s, description = %s, flags_element = %s\n",
988 name, description, flags_element);
990 /* If this is the first image, allocate the struct wim_info. Otherwise
991 * use the existing struct wim_info. */
993 wim_info = w->wim_info;
995 DEBUG("Allocing struct wim_info with 1 image\n");
996 wim_info = CALLOC(1, sizeof(struct wim_info));
998 ERROR("Could not allocate WIM information struct--- "
1000 return WIMLIB_ERR_NOMEM;
1004 image_info = add_image_info_struct(wim_info);
1008 if (!(image_info->name = STRDUP(name)))
1011 if (description && !(image_info->description = STRDUP(description)))
1013 if (flags_element && !(image_info->flags = STRDUP(flags_element)))
1016 w->wim_info = wim_info;
1017 image_info->index = wim_info->num_images;
1018 image_info->creation_time = get_timestamp();
1019 xml_update_image_info(w, image_info->index);
1023 destroy_image_info(image_info);
1026 wim_info->num_images--;
1029 ERROR("Out of memory!\n");
1030 return WIMLIB_ERR_NOMEM;
1033 /* Prints information about the specified image from struct wim_info structure.
1034 * @image may be WIM_ALL_IMAGES. */
1035 void print_image_info(const struct wim_info *wim_info, int image)
1038 const struct image_info *image_info;
1044 if (image == WIM_ALL_IMAGES) {
1045 for (i = 1; i <= wim_info->num_images; i++)
1046 print_image_info(wim_info, i);
1048 image_info = &wim_info->images[image - 1];
1050 printf("Index: %"PRIu64"\n",
1052 printf("Name: %s\n",
1055 /* Always print the Description: part even if there is no
1057 if (image_info->description)
1058 desc = image_info->description;
1061 printf("Description: %s\n", desc);
1063 if (image_info->display_name)
1064 printf("Display Name: %s\n",
1065 image_info->display_name);
1067 if (image_info->display_description)
1068 printf("Display Description: %s\n",
1069 image_info->display_description);
1071 printf("Directory Count: %"PRIu64"\n",
1072 image_info->dir_count);
1073 printf("File Count: %"PRIu64"\n",
1074 image_info->file_count);
1075 printf("Total Bytes: %"PRIu64"\n",
1076 image_info->total_bytes);
1077 printf("Hard Link Bytes: %"PRIu64"\n",
1078 image_info->hard_link_bytes);
1080 ctime = ms_timestamp_to_unix(image_info->creation_time);
1081 mtime = ms_timestamp_to_unix(image_info->last_modification_time);
1083 printf("Creation Time: %s", asctime(localtime(&ctime)));
1084 printf("Last Modification Time: %s", asctime(localtime(&mtime)));
1085 if (image_info->windows_info_exists)
1086 print_windows_info(&image_info->windows_info);
1087 if (image_info->flags)
1088 printf("Flags: %s\n", image_info->flags);
1094 * Reads the XML data from a WIM file.
1096 int read_xml_data(FILE *fp, const struct resource_entry *res, u8 **xml_data_ret,
1097 struct wim_info **info_ret)
1104 DEBUG("XML data is %"PRIu64" bytes at offset %"PRIu64"\n",
1105 (u64)res->size, res->offset);
1107 if (resource_is_compressed(res)) {
1108 ERROR("XML data is supposed to be uncompressed!\n");
1109 ret = WIMLIB_ERR_XML;
1112 if (res->size < 2) {
1113 ERROR("XML data must be at least 2 bytes!\n");
1114 ret = WIMLIB_ERR_XML;
1118 xml_data = MALLOC(res->size + 2);
1120 ret = WIMLIB_ERR_NOMEM;
1123 ret = read_full_resource(fp, res->size, res->size, res->offset,
1124 WIM_COMPRESSION_TYPE_NONE, xml_data);
1128 xml_data[res->size] = 0;
1129 xml_data[res->size + 1] = 0;
1131 DEBUG("Parsing XML using libxml2 to create XML tree.\n");
1133 doc = xmlReadMemory(xml_data, res->size, "noname.xml", "UTF-16", 0);
1137 ERROR("Failed to parse XML data!\n");
1138 ret = WIMLIB_ERR_XML;
1142 DEBUG("Constructing WIM information structure from XML tree.\n");
1144 root = xmlDocGetRootElement(doc);
1146 ERROR("Empty XML document!\n");
1147 ret = WIMLIB_ERR_XML;
1151 if (!node_is_element(root) || !node_name_is(root, "WIM")) {
1152 ERROR("Expected <WIM> for the root XML element! "
1153 "(found <%s>)\n", root->name);
1154 ret = WIMLIB_ERR_XML;
1158 ret = xml_read_wim_info(root, info_ret);
1162 DEBUG("Freeing XML tree.\n");
1166 *xml_data_ret = xml_data;
1177 #define CHECK_RET ({ if (ret < 0) { \
1178 ERROR("Error writing XML data!\n"); \
1179 ret = WIMLIB_ERR_WRITE; \
1184 * Writes XML data to a WIM file.
1186 * If @total_bytes is non-zero, it specifies what to write to the TOTALBYTES
1187 * element in the XML data. If zero, TOTALBYTES is given the default value of
1188 * the offset of the XML data.
1190 int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
1194 xmlTextWriter *writer;
1199 const xmlChar *content;
1202 size_t bytes_written;
1204 wimlib_assert(image == WIM_ALL_IMAGES ||
1205 (wim_info != NULL && image >= 1 &&
1206 image <= wim_info->num_images));
1208 /* The contents of the <TOTALBYTES> element in the XML data, under the
1209 * <WIM> element not the <IMAGE> element, is (for non-spit WIMs) the
1210 * size of the WIM file excluding the XML data and integrity table,
1211 * which is the current offset, since the XML data goes at the end of
1212 * the WIM file before the integrity table. */
1213 if (total_bytes == 0) {
1214 total_bytes = ftello(out);
1215 if (total_bytes == (u64)-1)
1216 return WIMLIB_ERR_WRITE;
1219 DEBUG("Creating XML buffer and text writer\n");
1220 buf = xmlBufferCreate();
1222 ERROR("Failed to allocate XML buffer!\n");
1223 ret = WIMLIB_ERR_NOMEM;
1226 writer = xmlNewTextWriterMemory(buf, 0);
1228 ERROR("Failed to allocate XML writer!\n");
1229 ret = WIMLIB_ERR_NOMEM;
1234 /* M$'s WIM files do not have XML declarations, so do not write one.
1235 * I'm not sure how we can force the document to be written in UTF-16
1236 * without calling xmlTextWriterStartDocument(), though, so currently it
1237 * is composed in a buffer UTF-8, then converted to UTF-16. */
1239 ret = xmlTextWriterStartDocument(writer, NULL, "UTF-16", NULL);
1243 DEBUG("Writing <WIM> element\n");
1244 ret = xmlTextWriterStartElement(writer, "WIM");
1247 ret = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
1252 num_images = wim_info->num_images;
1255 DEBUG("Writing %u <IMAGE> elements\n", num_images);
1257 for (i = 1; i <= num_images; i++) {
1258 if (image != WIM_ALL_IMAGES && i != image)
1260 DEBUG("Writing <IMAGE> element for image %d\n", i);
1261 ret = xml_write_image_info(writer, &wim_info->images[i - 1]);
1265 ret = xmlTextWriterEndElement(writer);
1268 ret = xmlTextWriterEndDocument(writer);
1271 DEBUG("Done composing XML document. Now converting to UTF-16 and "
1272 "writing it to the output file.\n");
1274 content = xmlBufferContent(buf);
1275 len = xmlBufferLength(buf);
1277 utf16_str = utf8_to_utf16(content, len, &utf16_len);
1279 ret = WIMLIB_ERR_NOMEM;
1283 if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF) ||
1284 ((bytes_written = fwrite(utf16_str, 1, utf16_len, out))
1286 ERROR("Error writing XML data: %m\n");
1287 ret = WIMLIB_ERR_WRITE;
1291 DEBUG("Cleaning up.\n");
1297 xmlFreeTextWriter(writer);
1304 /* Returns the name of the specified image. */
1305 WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image)
1307 DEBUG("Getting the name of image %d\n", image);
1308 if (image < 1 || image > w->hdr.image_count)
1311 return w->wim_info->images[image - 1].name;
1314 /* Returns the description of the specified image. */
1315 WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w,
1318 DEBUG("Getting the description of image %d\n", image);
1319 if (image < 1 || image > w->hdr.image_count)
1322 return w->wim_info->images[image - 1].description;
1325 /* Determines if an image name is already used by some image in the WIM. */
1326 WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name)
1330 DEBUG("Checking to see if the image name `%s' is already "
1332 if (!name || !w->wim_info)
1334 for (i = 1; i <= w->wim_info->num_images; i++)
1335 if (strcmp(w->wim_info->images[i - 1].name, name) == 0)
1341 WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp)
1343 DEBUG("Extracting the XML data.\n");
1344 if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) !=
1345 w->hdr.xml_res_entry.size) {
1346 ERROR("Failed to extract XML data!\n");
1347 return WIMLIB_ERR_WRITE;
1352 /* Sets the name of an image in the WIM. */
1353 WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name)
1358 DEBUG("Setting the name of image %d to %s\n", image, name);
1360 if (!name || !*name) {
1361 ERROR("Must specify a non-empty string for the image "
1363 return WIMLIB_ERR_INVALID_PARAM;
1365 if (image < 1 || image > w->hdr.image_count) {
1366 ERROR("%d is not a valid image!\n", image);
1367 return WIMLIB_ERR_INVALID_IMAGE;
1370 for (i = 1; i <= w->hdr.image_count; i++) {
1373 if (strcmp(w->wim_info->images[i - 1].name, name) == 0) {
1374 ERROR("The name `%s' is already used for image %d!\n",
1376 return WIMLIB_ERR_IMAGE_NAME_COLLISION;
1382 ERROR("Out of memory!\n");
1383 return WIMLIB_ERR_NOMEM;
1385 FREE(w->wim_info->images[image - 1].name);
1386 w->wim_info->images[image - 1].name = p;
1390 /* Sets the description of an image in the WIM. */
1391 WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image,
1392 const char *description)
1396 DEBUG("Setting the description of image %d to %s\n", image,
1399 if (image < 1 || image > w->hdr.image_count) {
1400 ERROR("%d is not a valid image!\n", image);
1401 return WIMLIB_ERR_INVALID_IMAGE;
1404 p = STRDUP(description);
1406 ERROR("Out of memory!\n");
1407 return WIMLIB_ERR_NOMEM;
1412 FREE(w->wim_info->images[image - 1].description);
1413 w->wim_info->images[image - 1].description = p;