X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fxml.c;h=3812ce1e19d7926e499a9c230e0bddb9664d02ea;hb=e4cdc80a6d033bb27ac0d1687ca32d0434673128;hp=d13944a76ebd8c03492b791bb7c3c2a179a4c259;hpb=643071b516a8d4f549064d3ce4875aafa615eaec;p=wimlib diff --git a/src/xml.c b/src/xml.c index d13944a7..3812ce1e 100644 --- a/src/xml.c +++ b/src/xml.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2012, 2013, 2015 Eric Biggers + * Copyright (C) 2012-2016 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -64,12 +64,14 @@ struct wim_xml_info { /* The number of WIM images (the length of 'images') */ int image_count; +#if TCHAR_IS_UTF16LE /* Temporary memory for UTF-8 => 'tchar' string translations. When an * API function needs to return a 'tchar' string, it uses one of these * array slots to hold the string and returns a pointer to it. */ tchar *strings[128]; size_t next_string_idx; size_t num_strings; +#endif }; /*----------------------------------------------------------------------------* @@ -144,18 +146,21 @@ node_get_timestamp(const xmlNode *node) static int tstr_get_utf8(const tchar *tstr, const xmlChar **utf8_ret) { - if (wimlib_mbs_is_utf8) { - *utf8_ret = (xmlChar *)tstr; - return 0; - } - return tstr_to_utf8_simple(tstr, (char **)utf8_ret); +#if TCHAR_IS_UTF16LE + return utf16le_to_utf8(tstr, tstrlen(tstr) * sizeof(tchar), + (char **)utf8_ret, NULL); +#else + *utf8_ret = (const xmlChar *)tstr; + return 0; +#endif } static void tstr_put_utf8(const xmlChar *utf8) { - if (!wimlib_mbs_is_utf8) - FREE((void *)utf8); +#if TCHAR_IS_UTF16LE + FREE((char *)utf8); +#endif } /* Retrieve the text contents of an XML element as a 'tchar' string. If not @@ -163,26 +168,29 @@ tstr_put_utf8(const xmlChar *utf8) static const tchar * node_get_ttext(struct wim_xml_info *info, xmlNode *node) { - const xmlChar *text; - tchar **ttext_p; + const xmlChar *text = node_get_text(node); - text = node_get_text(node); +#if TCHAR_IS_UTF16LE + tchar **ttext_p; - if (!text || wimlib_mbs_is_utf8) - return (const tchar *)text; + if (!text) + return NULL; ttext_p = &info->strings[info->next_string_idx]; if (info->num_strings >= ARRAY_LEN(info->strings)) { FREE(*ttext_p); *ttext_p = NULL; } - if (utf8_to_tstr_simple(text, ttext_p)) + if (utf8_to_tstr(text, strlen(text), ttext_p, NULL)) return NULL; if (info->num_strings < ARRAY_LEN(info->strings)) info->num_strings++; info->next_string_idx++; info->next_string_idx %= ARRAY_LEN(info->strings); return *ttext_p; +#else + return text; +#endif } /* Unlink the specified node from its parent, then free it (recursively). */ @@ -335,13 +343,41 @@ static struct wim_xml_info * alloc_wim_xml_info(void) { struct wim_xml_info *info = MALLOC(sizeof(*info)); +#if TCHAR_IS_UTF16LE if (info) { info->next_string_idx = 0; info->num_strings = 0; } +#endif return info; } +static bool +parse_index(xmlChar **pp, u32 *index_ret) +{ + xmlChar *p = *pp; + u32 index = 0; + + *p++ = '\0'; /* overwrite '[' */ + while (*p >= '0' && *p <= '9') { + u32 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 +398,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; + u32 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; @@ -476,37 +522,6 @@ xml_set_ttext_by_path(xmlNode *root, const xmlChar *path, const tchar *ttext) } } -/* Sets a string property for the specified WIM image. */ -static int -set_image_property(WIMStruct *wim, int image, const xmlChar *name, - const tchar *value) -{ - struct wim_xml_info *info = wim->xml_info; - - if (image < 1 || image > info->image_count) - return WIMLIB_ERR_INVALID_IMAGE; - - return xml_set_ttext_by_path(info->images[image - 1], name, value); -} - -/* Gets a string property for the specified WIM image as a 'tchar' string. - * Returns a pointer to the property value if found; NULL if the image doesn't - * exist; or 'default_value' if the property doesn't exist in the image or if - * the property value could not be translated to a 'tchar' string. */ -static const tchar * -get_image_property(const WIMStruct *wim, int image, const xmlChar *name, - const tchar *default_value) -{ - struct wim_xml_info *info = wim->xml_info; - const tchar *value; - - if (image < 1 || image > info->image_count) - return NULL; - - value = xml_get_ttext_by_path(info, info->images[image - 1], name); - return value ? value : default_value; -} - /* Unlink and return the node which represents the INDEX attribute of the * specified IMAGE element. */ static xmlAttr * @@ -604,8 +619,10 @@ xml_free_info_struct(struct wim_xml_info *info) if (info) { xmlFreeDoc(info->doc); FREE(info->images); + #if TCHAR_IS_UTF16LE for (size_t i = 0; i < info->num_strings; i++) FREE(info->strings[i]); + #endif FREE(info); } } @@ -716,7 +733,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; } @@ -809,7 +825,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); @@ -856,6 +875,7 @@ xml_delete_image(struct wim_xml_info *info, int image) #define PROCESSOR_ARCHITECTURE_MSIL 8 #define PROCESSOR_ARCHITECTURE_AMD64 9 #define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 +#define PROCESSOR_ARCHITECTURE_ARM64 12 static const tchar * describe_arch(u64 arch) @@ -866,6 +886,7 @@ describe_arch(u64 arch) [PROCESSOR_ARCHITECTURE_ARM] = T("ARM"), [PROCESSOR_ARCHITECTURE_IA64] = T("ia64"), [PROCESSOR_ARCHITECTURE_AMD64] = T("x86_64"), + [PROCESSOR_ARCHITECTURE_ARM64] = T("ARM64"), }; if (arch < ARRAY_LEN(descriptions) && descriptions[arch] != NULL) @@ -920,11 +941,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')); @@ -1017,7 +1039,7 @@ xml_print_image_info(struct wim_xml_info *info, int image) *----------------------------------------------------------------------------*/ static int -image_node_get_index(const xmlNode *node) +image_node_get_index(xmlNode *node) { u64 v = node_get_number((const xmlNode *)xmlHasProp(node, "INDEX"), 10); return min(v, INT_MAX); @@ -1380,13 +1402,19 @@ wimlib_image_name_in_use(const WIMStruct *wim, const tchar *name) WIMLIBAPI const tchar * wimlib_get_image_name(const WIMStruct *wim, int image) { - return get_image_property(wim, image, "NAME", T("")); + const struct wim_xml_info *info = wim->xml_info; + const tchar *name; + + if (image < 1 || image > info->image_count) + return NULL; + name = wimlib_get_image_property(wim, image, T("NAME")); + return name ? name : T(""); } WIMLIBAPI const tchar * wimlib_get_image_description(const WIMStruct *wim, int image) { - return get_image_property(wim, image, "DESCRIPTION", NULL); + return wimlib_get_image_property(wim, image, T("DESCRIPTION")); } WIMLIBAPI const tchar * @@ -1395,12 +1423,15 @@ wimlib_get_image_property(const WIMStruct *wim, int image, { const xmlChar *name; const tchar *value; + struct wim_xml_info *info = wim->xml_info; if (!property_name || !*property_name) return NULL; + if (image < 1 || image > info->image_count) + return NULL; if (tstr_get_utf8(property_name, &name)) return NULL; - value = get_image_property(wim, image, name, NULL); + value = xml_get_ttext_by_path(info, info->images[image - 1], name); tstr_put_utf8(name); return value; } @@ -1408,22 +1439,19 @@ wimlib_get_image_property(const WIMStruct *wim, int image, WIMLIBAPI int wimlib_set_image_name(WIMStruct *wim, int image, const tchar *name) { - if (image_name_in_use(wim, name, image)) - return WIMLIB_ERR_IMAGE_NAME_COLLISION; - - return set_image_property(wim, image, "NAME", name); + return wimlib_set_image_property(wim, image, T("NAME"), name); } WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *wim, int image, const tchar *description) { - return set_image_property(wim, image, "DESCRIPTION", description); + return wimlib_set_image_property(wim, image, T("DESCRIPTION"), description); } WIMLIBAPI int wimlib_set_image_flags(WIMStruct *wim, int image, const tchar *flags) { - return set_image_property(wim, image, "FLAGS", flags); + return wimlib_set_image_property(wim, image, T("FLAGS"), flags); } WIMLIBAPI int @@ -1431,15 +1459,23 @@ wimlib_set_image_property(WIMStruct *wim, int image, const tchar *property_name, const tchar *property_value) { const xmlChar *name; + struct wim_xml_info *info = wim->xml_info; int ret; if (!property_name || !*property_name) return WIMLIB_ERR_INVALID_PARAM; + if (image < 1 || image > info->image_count) + return WIMLIB_ERR_INVALID_IMAGE; + + if (!tstrcmp(property_name, T("NAME")) && + image_name_in_use(wim, property_value, image)) + return WIMLIB_ERR_IMAGE_NAME_COLLISION; + ret = tstr_get_utf8(property_name, &name); if (ret) return ret; - ret = set_image_property(wim, image, name, property_value); + ret = xml_set_ttext_by_path(info->images[image - 1], name, property_value); tstr_put_utf8(name); return ret; }