From f249ba1f7198e491c8e0b794a748095cdd1278a7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 19 Dec 2015 16:32:22 -0600 Subject: [PATCH] xml.c: support numerically indexed elements in wimlib_{get,set}_image_property() --- include/wimlib.h | 16 ++++++++++++++-- src/xml.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/include/wimlib.h b/include/wimlib.h index 09462278..10f9bb7e 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -3186,7 +3186,11 @@ wimlib_get_image_name(const WIMStruct *wim, int image); * "TOTALBYTES". The name can contain forward slashes to indicate a nested * XML element; for example, "WINDOWS/VERSION/BUILD" indicates the BUILD * element nested within the VERSION element nested within the WINDOWS - * element. The [ character is reserved for future use. + * element. Since wimlib v1.8.4, a bracketed number can be used to + * indicate one of several identically-named elements; for example, + * "WINDOWS/LANGUAGES/LANGUAGE[2]" indicates the second "LANGUAGE" element + * nested within the "WINDOWS/LANGUAGES" element. Note that element names + * are case sensitive. * * @return * The property's value as a ::wimlib_tchar string, or @c NULL if there is @@ -4043,6 +4047,13 @@ wimlib_set_image_name(WIMStruct *wim, int image, const wimlib_tchar *name); * @param property_name * The name of the image property in the same format documented for * wimlib_get_image_property(). + *
+ * Note: if creating a new element using a bracketed index such as + * "WINDOWS/LANGUAGES/LANGUAGE[2]", the highest index that can be specified + * is one greater than the number of existing elements with that same name, + * excluding the index. That means that if you are adding a list of new + * elements, they must be added sequentially from the first index (1) to + * the last index (n). * @param property_value * If not NULL and not empty, the property is set to this value. * Otherwise, the property is removed from the XML document. @@ -4052,7 +4063,8 @@ wimlib_set_image_name(WIMStruct *wim, int image, const wimlib_tchar *name); * @retval ::WIMLIB_ERR_INVALID_IMAGE * @p image does not exist in @p wim. * @retval ::WIMLIB_ERR_INVALID_PARAM - * @p property_name has an unsupported format. + * @p property_name has an unsupported format, or @p property_name included + * a bracketed index that was too high. */ extern int wimlib_set_image_property(WIMStruct *wim, int image, diff --git a/src/xml.c b/src/xml.c index 8280e8ed..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; -- 2.43.0