*/
/*
- * 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
/* 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
};
/*----------------------------------------------------------------------------*
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
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). */
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)
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;
}
}
-/* 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 *
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);
}
}
}
/*
- * 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.
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;
xmlFreeNode(totalbytes_node);
xmlFreeNode(hardlinkbytes_node);
xmlFreeNode(lastmodificationtime_node);
- WARNING("Failed to update image information!");
return WIMLIB_ERR_NOMEM;
}
* 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
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);
#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)
[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)
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'));
* Reading and writing the XML data *
*----------------------------------------------------------------------------*/
-static unsigned
-image_node_get_index(const xmlNode *node)
+static int
+image_node_get_index(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. */
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;
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;
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"));
}
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)
{
- 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 *
{
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;
}
WIMLIBAPI int
wimlib_set_image_name(WIMStruct *wim, int image, const tchar *name)
{
- if (wimlib_image_name_in_use(wim, name))
- 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
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;
}