X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fxml.c;h=d46470653ab4149d15fa5dfef347844034e32363;hp=60643756ac7f1dde86c559bb20ee2af5455f3585;hb=f249ba1f7198e491c8e0b794a748095cdd1278a7;hpb=62458ef728064652932d49fbab1116b2f2462fa8 diff --git a/src/xml.c b/src/xml.c index 60643756..d4647065 100644 --- a/src/xml.c +++ b/src/xml.c @@ -342,6 +342,32 @@ alloc_wim_xml_info(void) return info; } +static bool +parse_index(xmlChar **pp, uint32_t *index_ret) +{ + xmlChar *p = *pp; + uint32_t index = 0; + + *p++ = '\0'; /* overwrite '[' */ + while (*p >= '0' && *p <= '9') { + uint32_t n = (index * 10) + (*p++ - '0'); + if (n < index) + return false; + index = n; + } + if (index == 0) + return false; + if (*p != ']') + return false; + p++; + if (*p != '/' && *p != '\0') + return false; + + *pp = p; + *index_ret = index; + return true; +} + static int do_xml_path_walk(xmlNode *node, const xmlChar *path, bool create, xmlNode **result_ret) @@ -362,34 +388,44 @@ do_xml_path_walk(xmlNode *node, const xmlChar *path, bool create, if (*p == '/') goto bad_syntax; - if (strchr(p, '[')) /* reserved for future use */ - goto bad_syntax; c = *p; while (c != '\0') { const xmlChar *name; xmlNode *child; + uint32_t index = 1; /* We have another path component. */ /* Parse the element name. */ name = p; - while (*p != '/' && *p != '\0') + while (*p != '/' && *p != '\0' && *p != '[') p++; if (p == name) /* empty name? */ goto bad_syntax; + + /* Handle a bracketed index, if one was specified. */ + if (*p == '[' && !parse_index(&p, &index)) + goto bad_syntax; + c = *p; *p = '\0'; /* Look for a matching child. */ node_for_each_child(node, child) - if (node_is_element(child, name)) + if (node_is_element(child, name) && !--index) goto next_step; /* No child matched the path. If create=false, the lookup * failed. If create=true, create the needed element. */ if (!create) return 0; + + /* We can't create an element at index 'n' if indices 1...n-1 + * didn't already exist. */ + if (index != 1) + return WIMLIB_ERR_INVALID_PARAM; + child = xmlNewChild(node, NULL, name, NULL); if (!child) return WIMLIB_ERR_NOMEM; @@ -667,8 +703,8 @@ xml_set_wimboot(struct wim_xml_info *info, int image) } /* - * Calculate what to put in the FILECOUNT, DIRCOUNT, TOTALBYTES, and - * HARDLINKBYTES elements of the specified WIM image. + * Update the DIRCOUNT, FILECOUNT, TOTALBYTES, HARDLINKBYTES, and + * LASTMODIFICATIONTIME elements for the specified WIM image. * * Note: since these stats are likely to be used for display purposes only, we * no longer attempt to duplicate WIMGAPI's weird bugs when calculating them. @@ -684,8 +720,8 @@ xml_update_image_info(WIMStruct *wim, int image) u64 total_bytes = 0; u64 hard_link_bytes = 0; u64 size; - xmlNode *filecount_node; xmlNode *dircount_node; + xmlNode *filecount_node; xmlNode *totalbytes_node; xmlNode *hardlinkbytes_node; xmlNode *lastmodificationtime_node; @@ -716,7 +752,6 @@ xml_update_image_info(WIMStruct *wim, int image) xmlFreeNode(totalbytes_node); xmlFreeNode(hardlinkbytes_node); xmlFreeNode(lastmodificationtime_node); - WARNING("Failed to update image information!"); return WIMLIB_ERR_NOMEM; } @@ -773,9 +808,9 @@ err: * Make a copy of the XML information for the image with index @src_image in the * @src_info XML document and append it to the @dest_info XML document. * - * In the process, the image's name and description will be changed to the - * values specified by @dest_image_name and @dest_image_description. Either or - * both may be NULL, which indicates that the corresponding element will not be + * In the process, change the image's name and description to the values + * specified by @dest_image_name and @dest_image_description. Either or both + * may be NULL, which indicates that the corresponding element will not be * included in the destination image. */ int @@ -809,7 +844,10 @@ xml_export_image(const struct wim_xml_info *src_info, int src_image, xmlFreeProp(unlink_index_attribute(dest_node)); - return append_image_node(dest_info, dest_node); + ret = append_image_node(dest_info, dest_node); + if (ret) + goto err; + return 0; err: xmlFreeNode(dest_node); @@ -920,11 +958,12 @@ print_windows_info(struct wim_xml_info *info, xmlNode *image_node) tprintf(T("Languages: ")); node_for_each_child(langs_node, lang_node) { - if (node_is_element(lang_node, "LANGUAGE")) { - tfputs(node_get_ttext(info, lang_node), stdout); - tputchar(T(' ')); - } - + if (!node_is_element(lang_node, "LANGUAGE")) + continue; + text = node_get_ttext(info, lang_node); + if (!text) + continue; + tprintf(T("%"TS" "), text); } tputchar(T('\n')); @@ -1016,10 +1055,11 @@ xml_print_image_info(struct wim_xml_info *info, int image) * Reading and writing the XML data * *----------------------------------------------------------------------------*/ -static unsigned +static int image_node_get_index(const xmlNode *node) { - return node_get_number((const xmlNode *)xmlHasProp(node, "INDEX"), 10); + u64 v = node_get_number((const xmlNode *)xmlHasProp(node, "INDEX"), 10); + return min(v, INT_MAX); } /* Prepare the 'images' array from the XML document tree. */ @@ -1027,8 +1067,8 @@ static int setup_images(struct wim_xml_info *info, xmlNode *root) { xmlNode *child; - unsigned index; - unsigned max_index = 0; + int index; + int max_index = 0; int ret; info->images = NULL; @@ -1346,8 +1386,8 @@ wimlib_extract_xml_data(WIMStruct *wim, FILE *fp) return ret; } -WIMLIBAPI bool -wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) +static bool +image_name_in_use(const WIMStruct *wim, const tchar *name, int excluded_image) { const struct wim_xml_info *info = wim->xml_info; const xmlChar *name_utf8; @@ -1361,6 +1401,8 @@ wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) if (tstr_get_utf8(name, &name_utf8)) return false; for (int i = 0; i < info->image_count && !found; i++) { + if (i + 1 == excluded_image) + continue; found = xmlStrEqual(name_utf8, xml_get_text_by_path( info->images[i], "NAME")); } @@ -1368,6 +1410,12 @@ wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) return found; } +WIMLIBAPI bool +wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) +{ + return image_name_in_use(wim, name, WIMLIB_NO_IMAGE); +} + WIMLIBAPI const tchar * wimlib_get_image_name(const WIMStruct *wim, int image) { @@ -1380,10 +1428,26 @@ wimlib_get_image_description(const WIMStruct *wim, int image) return get_image_property(wim, image, "DESCRIPTION", NULL); } +WIMLIBAPI const tchar * +wimlib_get_image_property(const WIMStruct *wim, int image, + const tchar *property_name) +{ + const xmlChar *name; + const tchar *value; + + if (!property_name || !*property_name) + return NULL; + if (tstr_get_utf8(property_name, &name)) + return NULL; + value = get_image_property(wim, image, name, NULL); + tstr_put_utf8(name); + return value; +} + WIMLIBAPI int wimlib_set_image_name(WIMStruct *wim, int image, const tchar *name) { - if (wimlib_image_name_in_use(wim, name)) + if (image_name_in_use(wim, name, image)) return WIMLIB_ERR_IMAGE_NAME_COLLISION; return set_image_property(wim, image, "NAME", name); @@ -1400,3 +1464,21 @@ wimlib_set_image_flags(WIMStruct *wim, int image, const tchar *flags) { return set_image_property(wim, image, "FLAGS", flags); } + +WIMLIBAPI int +wimlib_set_image_property(WIMStruct *wim, int image, const tchar *property_name, + const tchar *property_value) +{ + const xmlChar *name; + int ret; + + if (!property_name || !*property_name) + return WIMLIB_ERR_INVALID_PARAM; + + ret = tstr_get_utf8(property_name, &name); + if (ret) + return ret; + ret = set_image_property(wim, image, name, property_value); + tstr_put_utf8(name); + return ret; +}