Various cleanups
authorEric Biggers <ebiggers3@gmail.com>
Sun, 16 Dec 2012 02:50:30 +0000 (20:50 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 16 Dec 2012 02:50:30 +0000 (20:50 -0600)
- wim_timestamp_to_str() instead of asctime(gmtime(wim_timestamp_to_unix()))
- inode_stream_lte() non-inline to save space
- new errors WIMLIB_ERR_CHAR_CONVERSION and WIMLIB_ERR_INVALID_PART_NUMBER
- write_xml_data():  Have libxml2 write directly to output file with UTF-16LE
  encoding (no need for in-memory buffer and converting to UTF-16LE afterwards)
- read_header(): Validate total_parts and part_number
- Fix a couple potential integer overflows
- Fix some indentation and phase out more 'uint' uses
- Remove some unneeded DEBUG() statements

14 files changed:
src/comp.h
src/decomp.h
src/dentry.c
src/header.c
src/lookup_table.c
src/lookup_table.h
src/lzx-comp.c
src/lzx-decomp.c
src/timestamp.h
src/util.c
src/wim.c
src/wimlib.h
src/xml.c
src/xml.h

index 76f958c..37b1f99 100644 (file)
@@ -20,7 +20,7 @@ struct output_bitstream {
        output_bitbuf_t bitbuf;
 
        /* Number of free bits in @bitbuf */
-       uint free_bits;
+       unsigned free_bits;
 
        u8 *bit_output;
        u8 *next_bit_output;
@@ -56,27 +56,27 @@ static inline int bitstream_put_two_bytes(struct output_bitstream *ostream,
 }
 
 struct lz_params {
-       uint min_match;
-       uint max_match;
-       uint nice_match;
-       uint good_match;
-       uint max_chain_len;
-       uint max_lazy_match;
-       uint too_far;
+       unsigned min_match;
+       unsigned max_match;
+       unsigned nice_match;
+       unsigned good_match;
+       unsigned max_chain_len;
+       unsigned max_lazy_match;
+       unsigned too_far;
 };
 
-typedef uint (*lz_record_match_t)(uint, uint, void *, void *);
-typedef uint (*lz_record_literal_t)(u8, void *);
+typedef unsigned (*lz_record_match_t)(unsigned, unsigned, void *, void *);
+typedef unsigned (*lz_record_literal_t)(u8, void *);
 
-extern uint lz_analyze_block(const u8 uncompressed_data[],
-                            uint uncompressed_len,
-                            u32 match_tab[],
-                            lz_record_match_t record_match,
-                            lz_record_literal_t record_literal,
-                            void *record_match_arg1,
-                            void *record_match_arg2,
-                            void *record_literal_arg,
-                            const struct lz_params *params);
+extern unsigned lz_analyze_block(const u8 uncompressed_data[],
+                                unsigned uncompressed_len,
+                                u32 match_tab[],
+                                lz_record_match_t record_match,
+                                lz_record_literal_t record_literal,
+                                void *record_match_arg1,
+                                void *record_match_arg2,
+                                void *record_literal_arg,
+                                const struct lz_params *params);
 
 extern int bitstream_put_bits(struct output_bitstream *ostream,
                              output_bitbuf_t bits, unsigned num_bits);
@@ -86,8 +86,10 @@ extern void init_output_bitstream(struct output_bitstream *ostream,
 
 extern int flush_output_bitstream(struct output_bitstream *ostream);
 
-extern void make_canonical_huffman_code(uint num_syms, uint max_codeword_len,
-                                       const u32 freq_tab[], u8 lens[],
+extern void make_canonical_huffman_code(unsigned num_syms,
+                                       unsigned max_codeword_len,
+                                       const u32 freq_tab[],
+                                       u8 lens[],
                                        u16 codewords[]);
 
 #endif /* _WIMLIB_COMP_H */
index 3ecf9d2..0bd2a69 100644 (file)
@@ -25,15 +25,15 @@ struct input_bitstream {
        const u8 *data;
 
        /* Number of bits in @bitbuf that are valid. */
-       uint bitsleft;
+       unsigned bitsleft;
 
        /* Number of words of data that are left. */
-       uint data_bytes_left;
+       unsigned data_bytes_left;
 };
 
 /* Initializes a bitstream to receive its input from @data. */
 static inline void init_input_bitstream(struct input_bitstream *istream,
-                                       const void *data, uint num_data_bytes)
+                                       const void *data, unsigned num_data_bytes)
 {
        istream->bitbuf          = 0;
        istream->bitsleft        = 0;
@@ -43,7 +43,7 @@ static inline void init_input_bitstream(struct input_bitstream *istream,
 
 /* Ensures that the bit buffer contains @num_bits bits. */
 static inline int bitstream_ensure_bits(struct input_bitstream *istream,
-                                       uint num_bits)
+                                       unsigned num_bits)
 {
        wimlib_assert(num_bits <= 16);
 
@@ -62,8 +62,8 @@ static inline int bitstream_ensure_bits(struct input_bitstream *istream,
                if (istream->data_bytes_left < 2)
                        return 1;
 
-               uint shift = sizeof(input_bitbuf_t) * 8 - 16 -
-                            istream->bitsleft;
+               unsigned shift = sizeof(input_bitbuf_t) * 8 - 16 -
+                                istream->bitsleft;
                istream->bitbuf |= (input_bitbuf_t)le16_to_cpu(
                                        *(u16*)istream->data) << shift;
                istream->data += 2;
@@ -75,8 +75,8 @@ static inline int bitstream_ensure_bits(struct input_bitstream *istream,
 
 /* Returns the next @num_bits bits in the bit buffer.  It must contain at least
  * @num_bits bits to call this function. */
-static inline uint bitstream_peek_bits(const struct input_bitstream *istream,
-                                      uint num_bits)
+static inline unsigned
+bitstream_peek_bits(const struct input_bitstream *istream, unsigned num_bits)
 {
        if (num_bits == 0)
                return 0;
@@ -86,7 +86,7 @@ static inline uint bitstream_peek_bits(const struct input_bitstream *istream,
 /* Removes @num_bits bits from the bit buffer.  It must contain at least
  * @num_bits bits to call this function. */
 static inline void bitstream_remove_bits(struct input_bitstream *istream,
-                                        uint num_bits)
+                                        unsigned num_bits)
 {
        istream->bitbuf <<= num_bits;
        istream->bitsleft -= num_bits;
@@ -94,7 +94,7 @@ static inline void bitstream_remove_bits(struct input_bitstream *istream,
 
 /* Reads and returns @num_bits bits from the input bitstream. */
 static inline int bitstream_read_bits(struct input_bitstream *istream,
-                                     uint num_bits, uint *n)
+                                     unsigned num_bits, unsigned *n)
 {
        int ret;
        ret = bitstream_ensure_bits(istream, num_bits);
@@ -129,10 +129,10 @@ static inline int bitstream_read_byte(struct input_bitstream *istream)
 
 /* Reads @num_bits bits from the bit buffer without checking to see if that many
  * bits are in the buffer or not. */
-static inline uint bitstream_read_bits_nocheck(struct input_bitstream *istream,
-                                              uint num_bits)
+static inline unsigned
+bitstream_read_bits_nocheck(struct input_bitstream *istream, unsigned num_bits)
 {
-       uint n = bitstream_peek_bits(istream, num_bits);
+       unsigned n = bitstream_peek_bits(istream, num_bits);
        bitstream_remove_bits(istream, num_bits);
        return n;
 }
@@ -156,11 +156,11 @@ extern int read_huffsym(struct input_bitstream *stream,
                        const u8 lengths[],
                        unsigned num_symbols,
                        unsigned table_bits,
-                       uint *n,
+                       unsigned *n,
                        unsigned max_codeword_len);
 
-extern int make_huffman_decode_table(u16 decode_table[], uint num_syms,
-                                    uint num_bits, const u8 lengths[],
-                                    uint max_codeword_len);
+extern int make_huffman_decode_table(u16 decode_table[], unsigned num_syms,
+                                    unsigned num_bits, const u8 lengths[],
+                                    unsigned max_codeword_len);
 
 #endif /* _WIMLIB_DECOMP_H */
index 5ea26d3..5460149 100644 (file)
@@ -756,49 +756,37 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        const u8 *hash;
        struct lookup_table_entry *lte;
        const struct inode *inode = dentry->d_inode;
-       time_t time;
-       char *p;
+       char buf[50];
 
        printf("[DENTRY]\n");
        printf("Length            = %"PRIu64"\n", dentry->length);
        printf("Attributes        = 0x%x\n", inode->attributes);
-       for (unsigned i = 0; i < ARRAY_LEN(file_attr_flags); i++)
+       for (size_t i = 0; i < ARRAY_LEN(file_attr_flags); i++)
                if (file_attr_flags[i].flag & inode->attributes)
                        printf("    FILE_ATTRIBUTE_%s is set\n",
                                file_attr_flags[i].name);
        printf("Security ID       = %d\n", inode->security_id);
        printf("Subdir offset     = %"PRIu64"\n", dentry->subdir_offset);
 
-       /* Translate the timestamps into something readable */
-       time = wim_timestamp_to_unix(inode->creation_time);
-       p = asctime(gmtime(&time));
-       *(strrchr(p, '\n')) = '\0';
-       printf("Creation Time     = %s UTC\n", p);
+       wim_timestamp_to_str(inode->creation_time, buf, sizeof(buf));
+       printf("Creation Time     = %s\n", buf);
 
-       time = wim_timestamp_to_unix(inode->last_access_time);
-       p = asctime(gmtime(&time));
-       *(strrchr(p, '\n')) = '\0';
-       printf("Last Access Time  = %s UTC\n", p);
+       wim_timestamp_to_str(inode->last_access_time, buf, sizeof(buf));
+       printf("Last Access Time  = %s\n", buf);
 
-       time = wim_timestamp_to_unix(inode->last_write_time);
-       p = asctime(gmtime(&time));
-       *(strrchr(p, '\n')) = '\0';
-       printf("Last Write Time   = %s UTC\n", p);
+       wim_timestamp_to_str(inode->last_write_time, buf, sizeof(buf));
+       printf("Last Write Time   = %s\n", buf);
 
        printf("Reparse Tag       = 0x%"PRIx32"\n", inode->reparse_tag);
        printf("Hard Link Group   = 0x%"PRIx64"\n", inode->ino);
        printf("Hard Link Group Size = %"PRIu32"\n", inode->link_count);
        printf("Number of Alternate Data Streams = %hu\n", inode->num_ads);
-       printf("Filename          = \"");
-       print_string(dentry->file_name, dentry->file_name_len);
-       puts("\"");
-       printf("Filename Length   = %hu\n", dentry->file_name_len);
        printf("Filename (UTF-8)  = \"%s\"\n", dentry->file_name_utf8);
-       printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);
-       printf("Short Name        = \"");
+       /*printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);*/
+       printf("Short Name (UTF-16LE) = \"");
        print_string(dentry->short_name, dentry->short_name_len);
        puts("\"");
-       printf("Short Name Length = %hu\n", dentry->short_name_len);
+       /*printf("Short Name Length = %hu\n", dentry->short_name_len);*/
        printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
        lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
        if (lte) {
index 2a7fe32..bb17209 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "wimlib_internal.h"
 #include "io.h"
+#include <limits.h>
 
 /* First 8 bytes in every WIM file. */
 static const u8 wim_magic_chars[WIM_MAGIC_LEN] = {
@@ -104,6 +105,15 @@ int read_header(FILE *fp, struct wim_header *hdr, int open_flags)
        p = get_u16(p, &hdr->part_number);
        p = get_u16(p, &hdr->total_parts);
 
+       if (hdr->total_parts == 0 ||
+           hdr->part_number == 0 ||
+           hdr->part_number > hdr->total_parts)
+       {
+               ERROR("Invalid WIM part number: %hu of %hu",
+                     hdr->part_number, hdr->total_parts);
+               return WIMLIB_ERR_INVALID_PART_NUMBER;
+       }
+
        if (!(open_flags & WIMLIB_OPEN_FLAG_SPLIT_OK)
            && (hdr->part_number != 1 || hdr->total_parts != 1))
        {
@@ -117,6 +127,11 @@ int read_header(FILE *fp, struct wim_header *hdr, int open_flags)
        DEBUG("part_number = %u, total_parts = %u, image_count = %u",
              hdr->part_number, hdr->total_parts, hdr->image_count);
 
+       if (hdr->image_count >= INT_MAX) {
+               ERROR("Invalid image count (%u)", hdr->image_count);
+               return WIMLIB_ERR_IMAGE_COUNT;
+       }
+
        /* Byte 48 */
 
        p = get_resource_entry(p, &hdr->lookup_table_res_entry);
@@ -240,14 +255,13 @@ struct hdr_flag hdr_flags[] = {
 WIMLIBAPI void wimlib_print_header(const WIMStruct *w)
 {
        const struct wim_header *hdr = &w->hdr;
-       uint i;
 
        printf("Magic Characters            = MSWIM\\000\\000\\000\n");
        printf("Header Size                 = %u\n", WIM_HEADER_DISK_SIZE);
        printf("Version                     = 0x%x\n", WIM_VERSION);
 
        printf("Flags                       = 0x%x\n", hdr->flags);
-       for (i = 0; i < ARRAY_LEN(hdr_flags); i++)
+       for (size_t i = 0; i < ARRAY_LEN(hdr_flags); i++)
                if (hdr_flags[i].flag & hdr->flags)
                        printf("    WIM_HDR_FLAG_%s is set\n", hdr_flags[i].name);
 
index 364f469..d3bc8b2 100644 (file)
@@ -686,6 +686,24 @@ int dentry_unresolve_ltes(struct dentry *dentry, void *ignore)
        return 0;
 }
 
+/*
+ * Returns the lookup table entry for stream @stream_idx of the inode, where
+ * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
+ * corresponds to an alternate data stream.
+ *
+ * This works for both resolved and un-resolved dentries.
+ */
+struct lookup_table_entry *
+inode_stream_lte(const struct inode *inode, unsigned stream_idx,
+                const struct lookup_table *table)
+{
+       if (inode->resolved)
+               return inode_stream_lte_resolved(inode, stream_idx);
+       else
+               return inode_stream_lte_unresolved(inode, stream_idx, table);
+}
+
+
 /* Return the lookup table entry for the unnamed data stream of an inode, or
  * NULL if there is none.
  *
index 592116b..7038cc5 100644 (file)
@@ -325,23 +325,10 @@ inode_stream_lte_unresolved(const struct inode *inode, unsigned stream_idx,
                                         inode->ads_entries[
                                                stream_idx - 1].hash);
 }
-/*
- * Returns the lookup table entry for stream @stream_idx of the inode, where
- * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
- * corresponds to an alternate data stream.
- *
- * This works for both resolved and un-resolved dentries.
- */
-static inline struct lookup_table_entry *
-inode_stream_lte(const struct inode *inode, unsigned stream_idx,
-                const struct lookup_table *table)
-{
-       if (inode->resolved)
-               return inode_stream_lte_resolved(inode, stream_idx);
-       else
-               return inode_stream_lte_unresolved(inode, stream_idx, table);
-}
 
+extern struct lookup_table_entry *
+inode_stream_lte(const struct inode *inode, unsigned stream_idx,
+                const struct lookup_table *table);
 
 static inline const u8 *inode_stream_hash_unresolved(const struct inode *inode,
                                                     unsigned stream_idx)
index 34251e3..f96d90c 100644 (file)
@@ -83,9 +83,6 @@ struct lzx_freq_tables {
        u32 aligned_freq_table[LZX_ALIGNEDTREE_NUM_SYMBOLS];
 };
 
-
-
-
 /* Returns the LZX position slot that corresponds to a given formatted offset.
  *
  * Logically, this returns the smallest i such that
@@ -146,19 +143,19 @@ static inline unsigned lzx_get_num_extra_bits(unsigned position_slot)
  * the frequency of symbols in the main, length, and aligned offset alphabets.
  * The return value is a 32-bit number that provides the match in an
  * intermediate representation documented below. */
-static u32 lzx_record_match(uint match_offset, uint match_len,
+static u32 lzx_record_match(unsigned match_offset, unsigned match_len,
                            void *__freq_tabs, void *__queue)
 {
        struct lzx_freq_tables *freq_tabs = __freq_tabs;
        struct lru_queue *queue = __queue;
-       uint formatted_offset;
-       uint position_slot;
-       uint position_footer = 0;
+       unsigned formatted_offset;
+       unsigned position_slot;
+       unsigned position_footer = 0;
        u32 match;
        u32 len_header;
        u32 len_pos_header;
-       uint len_footer;
-       uint adjusted_match_len;
+       unsigned len_footer;
+       unsigned adjusted_match_len;
 
        wimlib_assert(match_len >= LZX_MIN_MATCH && match_len <= LZX_MAX_MATCH);
        wimlib_assert(match_offset != 0);
@@ -261,21 +258,21 @@ static u32 lzx_record_match(uint match_offset, uint match_len,
  *                     main, length, and aligned offset Huffman codes.
  */
 static int lzx_write_match(struct output_bitstream *out, int block_type,
-                               u32 match, const struct lzx_codes *codes)
+                          u32 match, const struct lzx_codes *codes)
 {
        /* low 8 bits are the match length minus 2 */
-       uint match_len_minus_2 = match & 0xff;
+       unsigned match_len_minus_2 = match & 0xff;
        /* Next 17 bits are the position footer */
-       uint position_footer = (match >> 8) & 0x1ffff;  /* 17 bits */
+       unsigned position_footer = (match >> 8) & 0x1ffff;      /* 17 bits */
        /* Next 6 bits are the position slot. */
-       uint position_slot = (match >> 25) & 0x3f;      /* 6 bits */
-       uint len_header;
-       uint len_footer;
-       uint len_pos_header;
-       uint main_symbol;
-       uint num_extra_bits;
-       uint verbatim_bits;
-       uint aligned_bits;
+       unsigned position_slot = (match >> 25) & 0x3f;  /* 6 bits */
+       unsigned len_header;
+       unsigned len_footer;
+       unsigned len_pos_header;
+       unsigned main_symbol;
+       unsigned num_extra_bits;
+       unsigned verbatim_bits;
+       unsigned aligned_bits;
        int ret;
 
        /* If the match length is less than MIN_MATCH (= 2) +
@@ -291,7 +288,7 @@ static int lzx_write_match(struct output_bitstream *out, int block_type,
                len_header = match_len_minus_2;
                /* No length footer-- mark it with a special
                 * value. */
-               len_footer = (uint)(-1);
+               len_footer = (unsigned)(-1);
        } else {
                len_header = LZX_NUM_PRIMARY_LENS;
                len_footer = match_len_minus_2 - LZX_NUM_PRIMARY_LENS;
@@ -315,7 +312,7 @@ static int lzx_write_match(struct output_bitstream *out, int block_type,
 
        /* If there is a length footer, output it using the
         * length Huffman code. */
-       if (len_footer != (uint)(-1)) {
+       if (len_footer != (unsigned)(-1)) {
                ret = bitstream_put_bits(out, codes->len_codewords[len_footer],
                                         codes->len_lens[len_footer]);
                if (ret != 0)
@@ -369,10 +366,10 @@ static int lzx_write_match(struct output_bitstream *out, int block_type,
 static int lzx_write_compressed_literals(struct output_bitstream *ostream,
                                         int block_type,
                                         const u32 match_tab[],
-                                        uint  num_compressed_literals,
+                                        unsigned  num_compressed_literals,
                                         const struct lzx_codes *codes)
 {
-       uint i;
+       unsigned i;
        u32 match;
        int ret;
 
@@ -417,20 +414,19 @@ static int lzx_write_compressed_literals(struct output_bitstream *ostream,
  * @num_symbols:       The number of symbols in the code.
  */
 static int lzx_write_compressed_tree(struct output_bitstream *out,
-                               const u8 lens[],
-                               uint num_symbols)
+                                    const u8 lens[], unsigned num_symbols)
 {
        /* Frequencies of the length symbols, including the RLE symbols (NOT the
         * actual lengths themselves). */
-       uint pretree_freqs[LZX_PRETREE_NUM_SYMBOLS];
+       unsigned pretree_freqs[LZX_PRETREE_NUM_SYMBOLS];
        u8 pretree_lens[LZX_PRETREE_NUM_SYMBOLS];
        u16 pretree_codewords[LZX_PRETREE_NUM_SYMBOLS];
        u8 output_syms[num_symbols * 2];
-       uint output_syms_idx;
-       uint cur_run_len;
-       uint i;
-       uint len_in_run;
-       uint additional_bits;
+       unsigned output_syms_idx;
+       unsigned cur_run_len;
+       unsigned i;
+       unsigned len_in_run;
+       unsigned additional_bits;
        char delta;
        u8 pretree_sym;
 
@@ -609,7 +605,7 @@ static void lzx_make_huffman_codes(const struct lzx_freq_tables *freq_tabs,
  * format as used in other file formats such as the cabinet format, where a bit
  * is reserved for that purpose. */
 static void do_call_insn_preprocessing(u8 uncompressed_data[],
-                                               uint uncompressed_data_len)
+                                      unsigned uncompressed_data_len)
 {
        int i = 0;
        int file_size = LZX_MAGIC_FILESIZE;
@@ -671,39 +667,37 @@ static const struct lz_params lzx_lz_params = {
  * not reduce its size, and @compressed_data will not contain the full
  * compressed data.
  */
-int lzx_compress(const void *__uncompressed_data, uint uncompressed_len,
-                void *compressed_data, uint *compressed_len_ret)
+int lzx_compress(const void *__uncompressed_data, unsigned uncompressed_len,
+                void *compressed_data, unsigned *compressed_len_ret)
 {
        struct output_bitstream ostream;
        u8 uncompressed_data[uncompressed_len + LZX_MAX_MATCH];
        struct lzx_freq_tables freq_tabs;
        struct lzx_codes codes;
        u32 match_tab[uncompressed_len];
-       struct lru_queue queue = {.R0 = 1, .R1 = 1, .R2 = 1};
-       uint num_matches;
-       uint compressed_len;
-       uint i;
+       struct lru_queue queue;
+       unsigned num_matches;
+       unsigned compressed_len;
+       unsigned i;
        int ret;
        int block_type = LZX_BLOCKTYPE_ALIGNED;
 
-       LZX_DEBUG("uncompressed_len = %u", uncompressed_len);
-
        if (uncompressed_len < 100)
                return 1;
 
-
        memset(&freq_tabs, 0, sizeof(freq_tabs));
+       queue.R0 = 1;
+       queue.R1 = 1;
+       queue.R2 = 1;
 
        /* The input data must be preprocessed. To avoid changing the original
         * input, copy it to a temporary buffer. */
        memcpy(uncompressed_data, __uncompressed_data, uncompressed_len);
 
-
        /* Before doing any actual compression, do the call instruction (0xe8
         * byte) translation on the uncompressed data. */
        do_call_insn_preprocessing(uncompressed_data, uncompressed_len);
 
-
        /* Determine the sequence of matches and literals that will be output,
         * and in the process, keep counts of the number of times each symbol
         * will be output, so that the Huffman trees can be made. */
@@ -714,8 +708,6 @@ int lzx_compress(const void *__uncompressed_data, uint uncompressed_len,
                                       &queue, freq_tabs.main_freq_table,
                                       &lzx_lz_params);
 
-       LZX_DEBUG("using %u matches", num_matches);
-
        lzx_make_huffman_codes(&freq_tabs, &codes);
 
        /* Initialize the output bitstream. */
@@ -776,14 +768,10 @@ int lzx_compress(const void *__uncompressed_data, uint uncompressed_len,
 
        compressed_len = ostream.bit_output - (u8*)compressed_data;
 
-       LZX_DEBUG("Compressed %u => %u bytes",
-                 uncompressed_len, compressed_len);
-
        *compressed_len_ret = compressed_len;
 
 #ifdef ENABLE_VERIFY_COMPRESSION
        /* Verify that we really get the same thing back when decompressing. */
-       LZX_DEBUG("Verifying the compressed data.");
        u8 buf[uncompressed_len];
        ret = lzx_decompress(compressed_data, compressed_len, buf,
                             uncompressed_len);
@@ -800,8 +788,6 @@ int lzx_compress(const void *__uncompressed_data, uint uncompressed_len,
                        abort();
                }
        }
-       LZX_DEBUG("Compression verified to be correct.");
 #endif
-
        return 0;
 }
index fb8b17e..73e6812 100644 (file)
@@ -135,7 +135,7 @@ struct lzx_tables {
  */
 static inline int read_huffsym_using_pretree(struct input_bitstream *istream,
                                             const u16 pretree_decode_table[],
-                                            const u8 pretree_lens[], uint *n)
+                                            const u8 pretree_lens[], unsigned *n)
 {
        return read_huffsym(istream, pretree_decode_table, pretree_lens,
                            LZX_PRETREE_NUM_SYMBOLS, LZX_PRETREE_TABLEBITS, n,
@@ -145,7 +145,7 @@ static inline int read_huffsym_using_pretree(struct input_bitstream *istream,
 /* Reads a Huffman-encoded symbol using the main tree. */
 static inline int read_huffsym_using_maintree(struct input_bitstream *istream,
                                              const struct lzx_tables *tables,
-                                             uint *n)
+                                             unsigned *n)
 {
        return read_huffsym(istream, tables->maintree_decode_table,
                            tables->maintree_lens, LZX_MAINTREE_NUM_SYMBOLS,
@@ -155,7 +155,7 @@ static inline int read_huffsym_using_maintree(struct input_bitstream *istream,
 /* Reads a Huffman-encoded symbol using the length tree. */
 static inline int read_huffsym_using_lentree(struct input_bitstream *istream,
                                             const struct lzx_tables *tables,
-                                            uint *n)
+                                            unsigned *n)
 {
        return read_huffsym(istream, tables->lentree_decode_table,
                            tables->lentree_lens, LZX_LENTREE_NUM_SYMBOLS,
@@ -165,7 +165,7 @@ static inline int read_huffsym_using_lentree(struct input_bitstream *istream,
 /* Reads a Huffman-encoded symbol using the aligned offset tree. */
 static inline int read_huffsym_using_alignedtree(struct input_bitstream *istream,
                                                 const struct lzx_tables *tables,
-                                                uint *n)
+                                                unsigned *n)
 {
        return read_huffsym(istream, tables->alignedtree_decode_table,
                            tables->alignedtree_lens,
@@ -186,14 +186,14 @@ static inline int read_huffsym_using_alignedtree(struct input_bitstream *istream
  *
  */
 static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[],
-                             uint num_lens)
+                             unsigned num_lens)
 {
        /* Declare the decoding table and length table for the pretree. */
        u16 pretree_decode_table[(1 << LZX_PRETREE_TABLEBITS) +
                                        (LZX_PRETREE_NUM_SYMBOLS * 2)];
        u8 pretree_lens[LZX_PRETREE_NUM_SYMBOLS];
-       uint i;
-       uint len;
+       unsigned i;
+       unsigned len;
        int ret;
 
        /* Read the code lengths of the pretree codes.  There are 20 lengths of
@@ -226,10 +226,10 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[],
                 * some number of the next lengths are all 0, or some number of
                 * the next lengths are all equal to the next symbol in the
                 * input. */
-               uint tree_code;
-               uint num_zeroes;
-               uint code;
-               uint num_same;
+               unsigned tree_code;
+               unsigned num_zeroes;
+               unsigned code;
+               unsigned num_same;
                char value;
 
                ret = read_huffsym_using_pretree(istream, pretree_decode_table,
@@ -307,16 +307,17 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[],
  *                     blocks, which contain this information in the header)
  */
 static int lzx_read_block_header(struct input_bitstream *istream,
-                                int *block_size_ret, int *block_type_ret,
+                                unsigned *block_size_ret,
+                                unsigned *block_type_ret,
                                 struct lzx_tables *tables,
                                 struct lru_queue *queue)
 {
        int ret;
        int block_type;
-       uint block_size;
+       unsigned block_size;
        int s;
        int i;
-       uint len;
+       unsigned len;
        int32_t R[3];
 
        ret = bitstream_ensure_bits(istream, 4);
@@ -492,14 +493,14 @@ static int lzx_decode_match(int main_element, int block_type,
                            struct lru_queue *queue,
                            struct input_bitstream *istream)
 {
-       uint length_header;
-       uint position_slot;
-       uint match_len;
-       uint match_offset;
-       uint additional_len;
-       uint num_extra_bits;
-       uint verbatim_bits;
-       uint aligned_bits;
+       unsigned length_header;
+       unsigned position_slot;
+       unsigned match_len;
+       unsigned match_offset;
+       unsigned additional_len;
+       unsigned num_extra_bits;
+       unsigned verbatim_bits;
+       unsigned aligned_bits;
        int ret;
        int i;
        u8 *match_dest;
@@ -652,7 +653,7 @@ static int lzx_decode_match(int main_element, int block_type,
  * format as used in other file formats, where a bit is reserved for that
  * purpose. */
 static void undo_call_insn_preprocessing(u8 uncompressed_data[],
-                                        uint uncompressed_data_len)
+                                        unsigned uncompressed_data_len)
 {
        int i = 0;
        int file_size = LZX_MAGIC_FILESIZE;
@@ -704,8 +705,8 @@ static int lzx_decompress_block(int block_type, int block_size, u8 *window,
                                struct lru_queue *queue,
                                struct input_bitstream *istream)
 {
-       uint bytes_remaining;
-       uint main_element;
+       unsigned bytes_remaining;
+       unsigned main_element;
        int match_len;
        int ret;
 
@@ -749,16 +750,16 @@ static int lzx_decompress_block(int block_type, int block_size, u8 *window,
  *
  * Return non-zero on failure.
  */
-int lzx_decompress(const void *compressed_data, uint compressed_len,
-                  void *uncompressed_data, uint uncompressed_len)
+int lzx_decompress(const void *compressed_data, unsigned compressed_len,
+                  void *uncompressed_data, unsigned uncompressed_len)
 {
-       struct lzx_tables       tables;
-       struct input_bitstream  istream;
-       struct lru_queue        queue;
-       uint                    bytes_remaining;
+       struct lzx_tables tables;
+       struct input_bitstream istream;
+       struct lru_queue queue;
+       unsigned bytes_remaining;
+       unsigned block_size;
+       unsigned block_type;
        int ret;
-       int block_size;
-       int block_type;
 
        LZX_DEBUG("lzx_decompress (compressed_data = %p, compressed_len = %d, "
                  "uncompressed_data = %p, uncompressed_len = %d).",
@@ -784,17 +785,17 @@ int lzx_decompress(const void *compressed_data, uint compressed_len,
        while (bytes_remaining != 0) {
 
                LZX_DEBUG("Reading block header.");
-               ret = lzx_read_block_header(&istream, &block_size, &block_type,
-                                                       &tables, &queue);
+               ret = lzx_read_block_header(&istream, &block_size,
+                                           &block_type, &tables, &queue);
                if (ret != 0)
                        return ret;
 
-               LZX_DEBUG("block_size = %d, bytes_remaining = %d.",
+               LZX_DEBUG("block_size = %u, bytes_remaining = %u",
                          block_size, bytes_remaining);
 
                if (block_size > bytes_remaining) {
                        ERROR("lzx_decompress(): Expected a block size of at "
-                             "most %d bytes (found %d bytes)",
+                             "most %u bytes (found %u bytes)",
                              bytes_remaining, block_size);
                        return 1;
                }
@@ -836,7 +837,6 @@ int lzx_decompress(const void *compressed_data, uint compressed_len,
 
                if (bytes_remaining != 0)
                        LZX_DEBUG("%d bytes remaining.", bytes_remaining);
-
        }
 
        if (uncompressed_len >= 10)
index 6b54954..406f6a5 100644 (file)
@@ -4,6 +4,7 @@
 #include "util.h"
 #include <sys/types.h>
 #include <sys/time.h>
+#include <time.h>
 
 #define intervals_per_second (1000000000ULL / 100ULL)
 #define intervals_per_microsecond (10)
@@ -51,7 +52,7 @@ static inline u64 timespec_to_wim_timestamp(const struct timespec *ts)
               + (u64)ts->tv_nsec / nanoseconds_per_interval;
 }
 
-
 extern u64 get_wim_timestamp();
+extern void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len);
 
 #endif
index 5509a43..01ba8f3 100644 (file)
@@ -112,6 +112,8 @@ static const char *error_strings[] = {
                = "Success",
        [WIMLIB_ERR_ALREADY_LOCKED]
                = "The WIM is already locked for writing",
+       [WIMLIB_ERR_CHAR_CONVERSION]
+               = "Failed to perform a conversion between UTF-8 and UTF-16LE",
        [WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE]
                = "Lookup table is compressed",
        [WIMLIB_ERR_DECOMPRESSION]
@@ -152,6 +154,8 @@ static const char *error_strings[] = {
                = "An entry in the WIM's lookup table is invalid",
        [WIMLIB_ERR_INVALID_PARAM]
                = "An invalid parameter was given",
+       [WIMLIB_ERR_INVALID_PART_NUMBER]
+               = "The part number or total parts of the WIM is invalid",
        [WIMLIB_ERR_INVALID_RESOURCE_HASH]
                = "The SHA1 message digest of a WIM resource did not match the expected value",
        [WIMLIB_ERR_INVALID_RESOURCE_SIZE]
@@ -533,4 +537,10 @@ u64 get_wim_timestamp()
        return timeval_to_wim_timestamp(&tv);
 }
 
-
+void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len)
+{
+       struct tm tm;
+       time_t t = wim_timestamp_to_unix(timestamp);
+       gmtime_r(&t, &tm);
+       strftime(buf, len, "%a %b %d %H:%M:%S %Y UTC", &tm);
+}
index 117361c..cbda006 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -28,6 +28,7 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <errno.h>
 
 #include "dentry.h"
 #include <unistd.h>
@@ -433,7 +434,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
                      wimlib_progress_func_t progress_func)
 {
        int ret;
-       uint xml_num_images;
+       int xml_num_images;
 
        DEBUG("Reading the WIM file `%s'", in_wim_path);
 
@@ -456,7 +457,10 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
        w->filename = realpath(in_wim_path, NULL);
        if (!w->filename) {
                ERROR_WITH_ERRNO("Failed to resolve WIM filename");
-               ret = WIMLIB_ERR_NOMEM;
+               if (errno == ENOMEM)
+                       ret = WIMLIB_ERR_NOMEM;
+               else
+                       ret = WIMLIB_ERR_OPEN;
                goto out_close;
        }
 
@@ -464,7 +468,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
        if (ret != 0)
                goto out_close;
 
-       DEBUG("Wim file contains %u images", w->hdr.image_count);
+       DEBUG("According to header, WIM contains %u images", w->hdr.image_count);
 
        /* If the boot index is invalid, print a warning and set it to 0 */
        if (w->hdr.boot_idx > w->hdr.image_count) {
@@ -564,7 +568,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
        }
 
        DEBUG("Done beginning read of WIM file `%s'.", in_wim_path);
-       return 0;
+       /*return 0;*/
 
        //
        // Everything is freed in wimlib_free() anyway, so no need to roll back
@@ -585,7 +589,6 @@ out_free_lookup_table:
 out_close:
        /*fclose(w->fp);*/
        /*w->fp = NULL;*/
-out:
        return ret;
 }
 
index a547d3a..084f704 100644 (file)
@@ -678,6 +678,7 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type,
 enum wimlib_error_code {
        WIMLIB_ERR_SUCCESS = 0,
        WIMLIB_ERR_ALREADY_LOCKED,
+       WIMLIB_ERR_CHAR_CONVERSION,
        WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE,
        WIMLIB_ERR_DECOMPRESSION,
        WIMLIB_ERR_DELETE_STAGING_DIR,
@@ -696,6 +697,7 @@ enum wimlib_error_code {
        WIMLIB_ERR_INVALID_INTEGRITY_TABLE,
        WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY,
        WIMLIB_ERR_INVALID_PARAM,
+       WIMLIB_ERR_INVALID_PART_NUMBER,
        WIMLIB_ERR_INVALID_RESOURCE_HASH,
        WIMLIB_ERR_INVALID_RESOURCE_SIZE,
        WIMLIB_ERR_INVALID_SECURITY_DATA,
index 9a0bded..a1e6f59 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
-#include "wimlib_internal.h"
 #include "dentry.h"
-#include "xml.h"
-#include "timestamp.h"
 #include "lookup_table.h"
+#include "timestamp.h"
+#include "wimlib_internal.h"
+#include "xml.h"
+
 #include <string.h>
-#include <time.h>
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/xmlwriter.h>
+#include <libxml/encoding.h>
+#include <limits.h>
 
 /* Structures used to form an in-memory representation of the XML data (other
  * than the raw parse tree from libxml). */
@@ -55,28 +57,28 @@ struct windows_info {
        char  *product_suite;
        char **languages;
        char  *default_language;
-       u64    num_languages;
+       size_t num_languages;
        char  *system_root;
        bool   windows_version_exists;
        struct windows_version windows_version;
 };
 
 struct image_info {
-       u64   index;
-       u64   dir_count;
-       u64   file_count;
-       u64   total_bytes;
-       u64   hard_link_bytes;
-       u64   creation_time;
-       u64   last_modification_time;
-       bool  windows_info_exists;
+       int index;
+       bool windows_info_exists;
+       u64 dir_count;
+       u64 file_count;
+       u64 total_bytes;
+       u64 hard_link_bytes;
+       u64 creation_time;
+       u64 last_modification_time;
        struct windows_info windows_info;
        char *name;
        char *description;
-       char  *display_name;
-       char  *display_description;
+       char *display_name;
+       char *display_description;
        union {
-               char  *flags;
+               char *flags;
                struct lookup_table *lookup_table;
        };
 };
@@ -117,11 +119,6 @@ static inline bool node_is_text(xmlNode *node)
        return node->type == XML_TEXT_NODE;
 }
 
-static inline bool node_is_attribute(xmlNode *node)
-{
-       return node->type == XML_ATTRIBUTE_NODE;
-}
-
 static inline bool node_name_is(xmlNode *node, const char *name)
 {
        /* For now, both upper case and lower case element names are accepted. */
@@ -158,10 +155,8 @@ static int node_get_string(const xmlNode *string_node, char **str)
        for_node_child(string_node, child) {
                if (node_is_text(child) && child->content) {
                        p = STRDUP(child->content);
-                       if (!p) {
-                               ERROR("Out of memory");
+                       if (!p)
                                return WIMLIB_ERR_NOMEM;
-                       }
                        break;
                }
        }
@@ -190,8 +185,8 @@ static u64 node_get_timestamp(const xmlNode *time_node)
 /* Used to sort an array of struct image_infos by their image indices. */
 static int sort_by_index(const void *p1, const void *p2)
 {
-       u64 index_1 = ((struct image_info*)p1)->index;
-       u64 index_2 = ((struct image_info*)p1)->index;
+       int index_1 = ((struct image_info*)p1)->index;
+       int index_2 = ((struct image_info*)p1)->index;
        if (index_1 < index_2)
                return -1;
        else if (index_1 > index_2)
@@ -204,15 +199,13 @@ static int sort_by_index(const void *p1, const void *p2)
 /* Frees memory allocated inside a struct windows_info structure. */
 static void destroy_windows_info(struct windows_info *windows_info)
 {
-       uint i;
-
        FREE(windows_info->product_name);
        FREE(windows_info->edition_id);
        FREE(windows_info->installation_type);
        FREE(windows_info->hal);
        FREE(windows_info->product_type);
        FREE(windows_info->product_suite);
-       for (i = 0; i < windows_info->num_languages; i++)
+       for (size_t i = 0; i < windows_info->num_languages; i++)
                FREE(windows_info->languages[i]);
        FREE(windows_info->languages);
        FREE(windows_info->default_language);
@@ -233,10 +226,9 @@ static void destroy_image_info(struct image_info *image_info)
 
 void free_wim_info(struct wim_info *info)
 {
-       uint i;
        if (info) {
                if (info->images) {
-                       for (i = 0; i < info->num_images; i++)
+                       for (int i = 0; i < info->num_images; i++)
                                destroy_image_info(&info->images[i]);
                        FREE(info->images);
                }
@@ -254,11 +246,11 @@ static void xml_read_windows_version(const xmlNode *version_node,
                if (!node_is_element(child))
                        continue;
                if (node_name_is(child, "MAJOR"))
-                       windows_version->major    = node_get_u64(child);
+                       windows_version->major = node_get_u64(child);
                else if (node_name_is(child, "MINOR"))
-                       windows_version->minor    = node_get_u64(child);
+                       windows_version->minor = node_get_u64(child);
                else if (node_name_is(child, "BUILD"))
-                       windows_version->build    = node_get_u64(child);
+                       windows_version->build = node_get_u64(child);
                else if (node_name_is(child, "SPBUILD"))
                        windows_version->sp_build = node_get_u64(child);
                else if (node_name_is(child, "SPLEVEL"))
@@ -270,40 +262,35 @@ static void xml_read_windows_version(const xmlNode *version_node,
  * */
 static int xml_read_languages(const xmlNode *languages_node,
                              char ***languages_ret,
-                             u64 *num_languages_ret,
+                             size_t *num_languages_ret,
                              char **default_language_ret)
 {
        xmlNode *child;
-       uint i;
-       uint num_languages;
+       size_t num_languages = 0;
        char **languages;
        int ret;
 
-       num_languages = 0;
        for_node_child(languages_node, child)
                if (node_is_element(child) && node_name_is(child, "LANGUAGE"))
                        num_languages++;
 
-       languages = CALLOC(num_languages, sizeof(char*));
-       if (!languages) {
-               ERROR("Out of memory");
+       languages = CALLOC(num_languages, sizeof(languages[0]));
+       if (!languages)
                return WIMLIB_ERR_NOMEM;
-       }
 
        *languages_ret = languages;
        *num_languages_ret = num_languages;
 
-       i = 0;
        ret = 0;
        for_node_child(languages_node, child) {
                if (!node_is_element(child))
                        continue;
                if (node_name_is(child, "LANGUAGE"))
-                       ret = node_get_string(child, &languages[i++]);
+                       ret = node_get_string(child, languages++);
                else if (node_name_is(child, "DEFAULT"))
                        ret = node_get_string(child, default_language_ret);
                if (ret != 0)
-                       return ret;
+                       break;
        }
        return ret;
 }
@@ -349,7 +336,6 @@ static int xml_read_windows_info(const xmlNode *windows_node,
                } else if (node_name_is(child, "HAL")) {
                        ret = node_get_string(child, &windows_info->hal);
                }
-
                if (ret != 0)
                        return ret;
        }
@@ -366,11 +352,10 @@ static int xml_read_image_info(xmlNode *image_node,
 
        index_prop = xmlGetProp(image_node, "INDEX");
        if (index_prop) {
-               char *tmp;
-               image_info->index = strtoul(index_prop, &tmp, 10);
+               image_info->index = atoi(index_prop);
                FREE(index_prop);
        } else {
-               image_info->index = 0;
+               image_info->index = 1;
        }
 
        ret = 0;
@@ -409,14 +394,13 @@ static int xml_read_image_info(xmlNode *image_node,
                        return ret;
        }
        if (!image_info->name) {
-               WARNING("Image with index %"PRIu64" has no name",
-                       image_info->index);
-               image_info->name = MALLOC(1);
-               if (!image_info->name) {
-                       ERROR("Out of memory");
+               char *empty_name;
+               WARNING("Image with index %d has no name", image_info->index);
+               empty_name = MALLOC(1);
+               if (!empty_name)
                        return WIMLIB_ERR_NOMEM;
-               }
-               image_info->name[0] = '\0';
+               *empty_name = '\0';
+               image_info->name = empty_name;
        }
        return ret;
 }
@@ -429,50 +413,63 @@ static int xml_read_wim_info(const xmlNode *wim_node,
        struct wim_info *wim_info;
        xmlNode *child;
        int ret;
-       uint num_images;
-       struct image_info *cur_image_info;
+       int num_images;
+       int i;
 
        wim_info = CALLOC(1, sizeof(struct wim_info));
-       if (!wim_info) {
-               ERROR("Out of memory");
+       if (!wim_info)
                return WIMLIB_ERR_NOMEM;
-       }
 
        /* Count how many images there are. */
        num_images = 0;
-       for_node_child(wim_node, child)
-               if (node_is_element(child) && node_name_is(child, "IMAGE"))
+       for_node_child(wim_node, child) {
+               if (node_is_element(child) && node_name_is(child, "IMAGE")) {
+                       if (num_images == INT_MAX) {
+                               return WIMLIB_ERR_IMAGE_COUNT;
+                       }
                        num_images++;
+               }
+       }
 
-       if (num_images == 0)
-               goto done;
+       if (num_images > 0) {
+               /* Allocate the array of struct image_infos and fill them in. */
+               wim_info->images = CALLOC(num_images, sizeof(wim_info->images[0]));
+               if (!wim_info->images) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto err;
+               }
+               wim_info->num_images = num_images;
+               i = 0;
+               for_node_child(wim_node, child) {
+                       if (!node_is_element(child))
+                               continue;
+                       if (node_name_is(child, "IMAGE")) {
+                               DEBUG("Found <IMAGE> tag");
+                               ret = xml_read_image_info(child,
+                                                         &wim_info->images[i]);
+                               if (ret != 0)
+                                       goto err;
+                               i++;
+                       } else if (node_name_is(child, "TOTALBYTES")) {
+                               wim_info->total_bytes = node_get_u64(child);
+                       }
+               }
 
-       /* Allocate the array of struct image_infos and fill them in. */
-       wim_info->images = CALLOC(num_images, sizeof(wim_info->images[0]));
-       if (!wim_info->images) {
-               ret = WIMLIB_ERR_NOMEM;
-               ERROR("Out of memory!");
-               goto err;
-       }
-       wim_info->num_images = num_images;
-       cur_image_info = wim_info->images;
-       for_node_child(wim_node, child) {
-               if (!node_is_element(child))
-                       continue;
-               if (node_name_is(child, "IMAGE")) {
-                       DEBUG("Found <IMAGE> tag");
-                       ret = xml_read_image_info(child, cur_image_info++);
-                       if (ret != 0)
-                               goto err;
-               } else if (node_name_is(child, "TOTALBYTES")) {
-                       wim_info->total_bytes = node_get_u64(child);
+               /* Sort the array of image info by image index. */
+               qsort(wim_info->images, num_images,
+                     sizeof(struct image_info), sort_by_index);
+
+               /* Make sure the image indices make sense */
+               for (i = 0; i < num_images; i++) {
+                       if (wim_info->images[i].index != i + 1) {
+                               ERROR("WIM images are not indexed [1...%d] "
+                                     "in XML data as expected",
+                                     num_images);
+                               return WIMLIB_ERR_IMAGE_COUNT;
+                       }
                }
-       }
 
-       /* Sort the array of struct image_infos by image index. */
-       qsort(wim_info->images, wim_info->num_images,
-             sizeof(struct image_info), sort_by_index);
-done:
+       }
        *wim_info_ret = wim_info;
        return 0;
 err:
@@ -480,10 +477,9 @@ err:
        return ret;
 }
 
-/* Prints the information contained in a struct windows_info structure. */
+/* Prints the information contained in a `struct windows_info'. */
 static void print_windows_info(const struct windows_info *windows_info)
 {
-       uint i;
        const struct windows_version *windows_version;
 
        printf("Architecture:           %s\n", get_arch(windows_info->arch));
@@ -501,7 +497,8 @@ static void print_windows_info(const struct windows_info *windows_info)
                       windows_info->installation_type);
 
        if (windows_info->hal)
-               printf("HAL:                    %s\n", windows_info->hal);
+               printf("HAL:                    %s\n",
+                      windows_info->hal);
 
        if (windows_info->product_type)
                printf("Product Type:           %s\n",
@@ -510,8 +507,9 @@ static void print_windows_info(const struct windows_info *windows_info)
        if (windows_info->product_suite)
                printf("Product Suite:          %s\n",
                       windows_info->product_suite);
+
        printf("Languages:              ");
-       for (i = 0; i < windows_info->num_languages; i++) {
+       for (size_t i = 0; i < windows_info->num_languages; i++) {
                fputs(windows_info->languages[i], stdout);
                putchar(' ');
        }
@@ -525,22 +523,22 @@ static void print_windows_info(const struct windows_info *windows_info)
        if (windows_info->windows_version_exists) {
                windows_version = &windows_info->windows_version;
                printf("Major Version:          %"PRIu64"\n",
-                               windows_version->major);
+                      windows_version->major);
                printf("Minor Version:          %"PRIu64"\n",
-                               windows_version->minor);
+                      windows_version->minor);
                printf("Build:                  %"PRIu64"\n",
-                               windows_version->build);
+                      windows_version->build);
                printf("Service Pack Build:     %"PRIu64"\n",
-                               windows_version->sp_build);
+                      windows_version->sp_build);
                printf("Service Pack Level:     %"PRIu64"\n",
-                               windows_version->sp_level);
+                      windows_version->sp_level);
        }
 }
 
 
-/* Writes the information contained in a struct windows_version structure to the XML
- * document being constructed in memory.  This is the <VERSION> element inside
- * the <WINDOWS> element. */
+/* Writes the information contained in a `struct windows_version' to the XML
+ * document being written.  This is the <VERSION> element inside the <WINDOWS>
+ * element. */
 static int xml_write_windows_version(xmlTextWriter *writer,
                                     const struct windows_version *version)
 {
@@ -550,35 +548,35 @@ static int xml_write_windows_version(xmlTextWriter *writer,
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "MAJOR", "%"PRIu64,
-                                                               version->major);
+                                            version->major);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "MINOR", "%"PRIu64,
-                                                               version->minor);
+                                            version->minor);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "BUILD", "%"PRIu64,
-                                                               version->build);
+                                            version->build);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "SPBUILD", "%"PRIu64,
-                                                               version->sp_build);
+                                            version->sp_build);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "SPLEVEL", "%"PRIu64,
-                                                               version->sp_level);
+                                            version->sp_level);
        if (rc < 0)
                return rc;
 
        return xmlTextWriterEndElement(writer); /* </VERSION> */
 }
 
-/* Writes the information contained in a struct windows_info structure to the XML
- * document being constructed in memory. This is the <WINDOWS> element. */
+/* Writes the information contained in a `struct windows_info' to the XML
+ * document being written. This is the <WINDOWS> element. */
 static int xml_write_windows_info(xmlTextWriter *writer,
                                  const struct windows_info *windows_info)
 {
@@ -587,52 +585,51 @@ static int xml_write_windows_info(xmlTextWriter *writer,
        if (rc < 0)
                return rc;
 
-
        rc = xmlTextWriterWriteFormatElement(writer, "ARCH", "%"PRIu64,
-                                                       windows_info->arch);
+                                            windows_info->arch);
        if (rc < 0)
                return rc;
 
        if (windows_info->product_name) {
                rc = xmlTextWriterWriteElement(writer, "PRODUCTNAME",
-                                                       windows_info->product_name);
+                                              windows_info->product_name);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->edition_id) {
                rc = xmlTextWriterWriteElement(writer, "EDITIONID",
-                                                       windows_info->edition_id);
+                                              windows_info->edition_id);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->installation_type) {
                rc = xmlTextWriterWriteElement(writer, "INSTALLATIONTYPE",
-                                                       windows_info->installation_type);
+                                              windows_info->installation_type);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->hal) {
                rc = xmlTextWriterWriteElement(writer, "HAL",
-                                                       windows_info->hal);
+                                              windows_info->hal);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->product_type) {
                rc = xmlTextWriterWriteElement(writer, "PRODUCTTYPE",
-                                               windows_info->product_type);
+                                              windows_info->product_type);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->product_suite) {
                rc = xmlTextWriterWriteElement(writer, "PRODUCTSUITE",
-                                               windows_info->product_suite);
-                       if (rc < 0)
-                               return rc;
+                                              windows_info->product_suite);
+               if (rc < 0)
+                       return rc;
        }
 
        if (windows_info->num_languages) {
@@ -640,14 +637,14 @@ static int xml_write_windows_info(xmlTextWriter *writer,
                if (rc < 0)
                        return rc;
 
-               for (int i = 0; i < windows_info->num_languages; i++) {
+               for (size_t i = 0; i < windows_info->num_languages; i++) {
                        rc = xmlTextWriterWriteElement(writer, "LANGUAGE",
-                                                       windows_info->languages[i]);
+                                                      windows_info->languages[i]);
                        if (rc < 0)
                                return rc;
                }
                rc = xmlTextWriterWriteElement(writer, "DEFAULT",
-                                               windows_info->default_language);
+                                              windows_info->default_language);
                if (rc < 0)
                        return rc;
 
@@ -664,9 +661,9 @@ static int xml_write_windows_info(xmlTextWriter *writer,
 
        if (windows_info->system_root) {
                rc = xmlTextWriterWriteElement(writer, "SYSTEMROOT",
-                                               windows_info->system_root);
-                       if (rc < 0)
-                               return rc;
+                                              windows_info->system_root);
+               if (rc < 0)
+                       return rc;
        }
 
        return xmlTextWriterEndElement(writer); /* </WINDOWS> */
@@ -697,7 +694,6 @@ static int xml_write_time(xmlTextWriter *writer, const char *element_name,
        return 0;
 }
 
-
 /* Writes an <IMAGE> element to the XML document. */
 static int xml_write_image_info(xmlTextWriter *writer,
                                const struct image_info *image_info)
@@ -707,38 +703,37 @@ static int xml_write_image_info(xmlTextWriter *writer,
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%"PRIu64,
-                                               image_info->index);
+       rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%d",
+                                              image_info->index);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "DIRCOUNT", "%"PRIu64,
-                                               image_info->dir_count);
+                                            image_info->dir_count);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "FILECOUNT", "%"PRIu64,
-                                               image_info->file_count);
+                                            image_info->file_count);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
-                                               image_info->total_bytes);
+                                            image_info->total_bytes);
        if (rc < 0)
                return rc;
 
        rc = xmlTextWriterWriteFormatElement(writer, "HARDLINKBYTES", "%"PRIu64,
-                                               image_info->hard_link_bytes);
+                                            image_info->hard_link_bytes);
        if (rc < 0)
                return rc;
 
-       rc = xml_write_time(writer, "CREATIONTIME",
-                                               image_info->creation_time);
+       rc = xml_write_time(writer, "CREATIONTIME", image_info->creation_time);
        if (rc < 0)
                return rc;
 
        rc = xml_write_time(writer, "LASTMODIFICATIONTIME",
-                                               image_info->last_modification_time);
+                           image_info->last_modification_time);
        if (rc < 0)
                return rc;
 
@@ -746,37 +741,37 @@ static int xml_write_image_info(xmlTextWriter *writer,
                rc = xml_write_windows_info(writer, &image_info->windows_info);
                if (rc < 0)
                        return rc;
-       } else {
-               DEBUG("<WINDOWS> tag does not exist.");
        }
 
        if (image_info->name) {
-               rc = xmlTextWriterWriteElement(writer, "NAME", image_info->name);
+               rc = xmlTextWriterWriteElement(writer, "NAME",
+                                              image_info->name);
                if (rc < 0)
                        return rc;
        }
+
        if (image_info->description) {
                rc = xmlTextWriterWriteElement(writer, "DESCRIPTION",
-                                                       image_info->description);
+                                              image_info->description);
                if (rc < 0)
                        return rc;
        }
        if (image_info->display_name) {
                rc = xmlTextWriterWriteElement(writer, "DISPLAYNAME",
-                                               image_info->display_name);
+                                              image_info->display_name);
                if (rc < 0)
                        return rc;
        }
        if (image_info->display_description) {
                rc = xmlTextWriterWriteElement(writer, "DISPLAYDESCRIPTION",
-                                               image_info->display_description);
+                                              image_info->display_description);
                if (rc < 0)
                        return rc;
        }
 
        if (image_info->flags) {
                rc = xmlTextWriterWriteElement(writer, "FLAGS",
-                               image_info->flags);
+                                              image_info->flags);
                if (rc < 0)
                        return rc;
        }
@@ -806,8 +801,6 @@ static struct image_info *add_image_info_struct(struct wim_info *wim_info)
 static int clone_windows_info(const struct windows_info *old,
                              struct windows_info *new)
 {
-       uint i;
-
        if (old->product_name && !(new->product_name = STRDUP(old->product_name)))
                return WIMLIB_ERR_NOMEM;
        if (old->edition_id && !(new->edition_id = STRDUP(old->edition_id)))
@@ -827,7 +820,7 @@ static int clone_windows_info(const struct windows_info *old,
                if (!new->languages)
                        return WIMLIB_ERR_NOMEM;
                new->num_languages = old->num_languages;
-               for (i = 0; i < new->num_languages; i++) {
+               for (size_t i = 0; i < new->num_languages; i++) {
                        if (!old->languages[i])
                                continue;
                        new->languages[i] = STRDUP(old->languages[i]);
@@ -905,6 +898,7 @@ int xml_export_image(const struct wim_info *old_wim_info,
 
        DEBUG("Copying XML data between WIM files for source image %d.", image);
 
+       wimlib_assert(old_wim_info != NULL);
        wimlib_assert(image >= 1 && image <= old_wim_info->num_images);
 
        if (*new_wim_info_p) {
@@ -921,7 +915,7 @@ int xml_export_image(const struct wim_info *old_wim_info,
 
        ret = clone_image_info(&old_wim_info->images[image - 1], image_info);
        if (ret != 0)
-               goto err;
+               goto err_destroy_image_info;
 
        image_info->index = new_wim_info->num_images;
 
@@ -929,19 +923,21 @@ int xml_export_image(const struct wim_info *old_wim_info,
                FREE(image_info->name);
                image_info->name = STRDUP(dest_image_name);
                if (!image_info->name)
-                       goto err;
+                       goto err_destroy_image_info;
        }
        if (dest_image_description) {
                FREE(image_info->description);
                image_info->description = STRDUP(dest_image_description);
                if (!image_info->description)
-                       goto err;
+                       goto err_destroy_image_info;
        }
        *new_wim_info_p = new_wim_info;
        return 0;
+err_destroy_image_info:
+       destroy_image_info(image_info);
 err:
-       ERROR("Out of memory");
-       free_wim_info(new_wim_info);
+       if (new_wim_info != *new_wim_info_p)
+               free_wim_info(new_wim_info);
        return WIMLIB_ERR_NOMEM;
 }
 
@@ -949,37 +945,41 @@ err:
 void xml_delete_image(struct wim_info **wim_info_p, int image)
 {
        struct wim_info *wim_info;
-       int i;
 
        DEBUG("Deleting image %d from the XML data.", image);
 
        wim_info = *wim_info_p;
 
-       wimlib_assert(wim_info);
+       wimlib_assert(wim_info != NULL);
        wimlib_assert(image >= 1 && image <= wim_info->num_images);
 
        destroy_image_info(&wim_info->images[image - 1]);
 
-       for (i = image - 1; i < wim_info->num_images - 1; i++) {
-               memcpy(&wim_info->images[i], &wim_info->images[i + 1],
-                                       sizeof(struct image_info));
-               wim_info->images[i].index--;
-       }
+       memcpy(&wim_info->images[image - 1],
+              &wim_info->images[image],
+              (wim_info->num_images - image) * sizeof(struct image_info));
 
        if (--wim_info->num_images == 0) {
                free_wim_info(wim_info);
                *wim_info_p = NULL;
+       } else {
+               for (int i = image - 1; i < wim_info->num_images; i++)
+                       wim_info->images[i].index--;
        }
 }
 
 size_t xml_get_max_image_name_len(const WIMStruct *w)
 {
-       size_t len = 0;
-       uint i;
-       uint num_images = w->wim_info->num_images;
-       for (i = 0; i < num_images; i++)
-               len = max(len, strlen(w->wim_info->images[i].name));
-       return len;
+       size_t max_len = 0;
+       if (w->wim_info) {
+               size_t len;
+               for (int i = 0; i < w->wim_info->num_images; i++) {
+                       len = strlen(w->wim_info->images[i].name);
+                       if (len > max_len)
+                               max_len = len;
+               }
+       }
+       return max_len;
 }
 
 #ifdef ENABLE_CUSTOM_MEMORY_ALLOCATOR
@@ -1062,6 +1062,13 @@ static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
        return 0;
 }
 
+/*
+ * Calculate what to put in the <FILECOUNT>, <DIRCOUNT>, <TOTALBYTES>, and
+ * <HARDLINKBYTES> elements of each <IMAGE>.
+ *
+ * Please note there is no official documentation for exactly how this is done.
+ * But, see calculate_dentry_statistics().
+ */
 void xml_update_image_info(WIMStruct *w, int image)
 {
        struct image_info *image_info;
@@ -1078,12 +1085,9 @@ void xml_update_image_info(WIMStruct *w, int image)
 
        flags_save = image_info->flags;
        image_info->lookup_table = w->lookup_table;
-
        for_dentry_in_tree(w->image_metadata[image - 1].root_dentry,
                           calculate_dentry_statistics,
                           image_info);
-
-       image_info->lookup_table = NULL;
        image_info->flags = flags_save;
        image_info->last_modification_time = get_wim_timestamp();
 }
@@ -1094,22 +1098,16 @@ int xml_add_image(WIMStruct *w, const char *name)
        struct wim_info *wim_info;
        struct image_info *image_info;
 
-       wimlib_assert(name);
-
-       DEBUG("Adding image: name = %s", name);
+       wimlib_assert(name != NULL);
 
        /* If this is the first image, allocate the struct wim_info.  Otherwise
         * use the existing struct wim_info. */
        if (w->wim_info) {
                wim_info = w->wim_info;
        } else {
-               DEBUG("Allocing struct wim_info with 1 image");
                wim_info = CALLOC(1, sizeof(struct wim_info));
-               if (!wim_info) {
-                       ERROR("Could not allocate WIM information struct--- "
-                             "out of memory");
+               if (!wim_info)
                        return WIMLIB_ERR_NOMEM;
-               }
        }
 
        image_info = add_image_info_struct(wim_info);
@@ -1131,7 +1129,6 @@ out_destroy_image_info:
 out_free_wim_info:
        if (wim_info != w->wim_info)
                FREE(wim_info);
-       ERROR("Out of memory");
        return WIMLIB_ERR_NOMEM;
 }
 
@@ -1141,14 +1138,13 @@ void print_image_info(const struct wim_info *wim_info, int image)
 {
        const struct image_info *image_info;
        const char *desc;
-       time_t time;
-       char *p;
+       char buf[50];
 
        wimlib_assert(image >= 1 && image <= wim_info->num_images);
 
        image_info = &wim_info->images[image - 1];
 
-       printf("Index:                  %"PRIu64"\n", image_info->index);
+       printf("Index:                  %d\n", image_info->index);
        printf("Name:                   %s\n", image_info->name);
 
        /* Always print the Description: part even if there is no
@@ -1172,17 +1168,11 @@ void print_image_info(const struct wim_info *wim_info, int image)
        printf("Total Bytes:            %"PRIu64"\n", image_info->total_bytes);
        printf("Hard Link Bytes:        %"PRIu64"\n", image_info->hard_link_bytes);
 
-       time = wim_timestamp_to_unix(image_info->creation_time);
-       p = asctime(gmtime(&time));
-       *(strrchr(p, '\n')) = '\0';
-
-       printf("Creation Time:          %s UTC\n", p);
+       wim_timestamp_to_str(image_info->creation_time, buf, sizeof(buf));
+       printf("Creation Time:          %s\n", buf);
 
-       time = wim_timestamp_to_unix(image_info->last_modification_time);
-       p = asctime(gmtime(&time));
-       *(strrchr(p, '\n')) = '\0';
-
-       printf("Last Modification Time: %s UTC\n", p);
+       wim_timestamp_to_str(image_info->creation_time, buf, sizeof(buf));
+       printf("Last Modification Time: %s\n", buf);
        if (image_info->windows_info_exists)
                print_windows_info(&image_info->windows_info);
        if (image_info->flags)
@@ -1193,7 +1183,7 @@ void print_image_info(const struct wim_info *wim_info, int image)
 /*
  * Reads the XML data from a WIM file.
  */
-int read_xml_data(FILE *fp, const struct resource_entry *res,
+int read_xml_data(FILE *fp, const struct resource_entry *res_entry,
                  u8 **xml_data_ret, struct wim_info **info_ret)
 {
        u8 *xml_data;
@@ -1202,35 +1192,39 @@ int read_xml_data(FILE *fp, const struct resource_entry *res,
        int ret;
 
        DEBUG("XML data is %"PRIu64" bytes at offset %"PRIu64"",
-             (u64)res->size, res->offset);
+             (u64)res_entry->size, res_entry->offset);
 
-       if (resource_is_compressed(res)) {
+       if (resource_is_compressed(res_entry)) {
                ERROR("XML data is supposed to be uncompressed");
                ret = WIMLIB_ERR_XML;
                goto out_cleanup_parser;
        }
-       if (res->size < 2) {
-               ERROR("XML data must be at least 2 bytes");
+
+       if (res_entry->size < 2) {
+               ERROR("XML data must be at least 2 bytes long");
                ret = WIMLIB_ERR_XML;
                goto out_cleanup_parser;
        }
 
-       xml_data = MALLOC(res->size + 2);
+       xml_data = MALLOC(res_entry->size + 2);
        if (!xml_data) {
                ret = WIMLIB_ERR_NOMEM;
                goto out_cleanup_parser;
        }
-       ret = read_uncompressed_resource(fp, res->offset, res->size, xml_data);
+
+       ret = read_uncompressed_resource(fp, res_entry->offset,
+                                        res_entry->size, xml_data);
        if (ret != 0)
                goto out_free_xml_data;
 
-       xml_data[res->size] = 0;
-       xml_data[res->size + 1] = 0;
-
-       DEBUG("Parsing XML using libxml2 to create XML tree.");
+       /* Null-terminate just in case */
+       xml_data[res_entry->size] = 0;
+       xml_data[res_entry->size + 1] = 0;
 
-       doc = xmlReadMemory(xml_data, res->size, "noname.xml", "UTF-16", 0);
+       DEBUG("Parsing XML using libxml2 to create XML tree");
 
+       doc = xmlReadMemory(xml_data, res_entry->size,
+                           "noname.xml", "UTF-16", 0);
 
        if (!doc) {
                ERROR("Failed to parse XML data");
@@ -1242,7 +1236,7 @@ int read_xml_data(FILE *fp, const struct resource_entry *res,
 
        root = xmlDocGetRootElement(doc);
        if (!root) {
-               ERROR("Empty XML document");
+               ERROR("WIM XML data is an empty XML document");
                ret = WIMLIB_ERR_XML;
                goto out_free_doc;
        }
@@ -1260,10 +1254,8 @@ int read_xml_data(FILE *fp, const struct resource_entry *res,
 
        DEBUG("Freeing XML tree.");
 
-       xmlFreeDoc(doc);
-       xmlCleanupParser();
        *xml_data_ret = xml_data;
-       return 0;
+       xml_data = NULL;
 out_free_doc:
        xmlFreeDoc(doc);
 out_free_xml_data:
@@ -1289,15 +1281,12 @@ out_cleanup_parser:
 int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
                   u64 total_bytes, struct resource_entry *out_res_entry)
 {
-       xmlBuffer     *buf;
+       xmlCharEncodingHandler *encoding_handler;
+       xmlOutputBuffer *out_buffer;
        xmlTextWriter *writer;
-       char          *utf16_str;
        int ret;
-       const xmlChar *content;
-       size_t len;
-       size_t utf16_len;
-       size_t bytes_written;
-       off_t start_offset, end_offset;
+       off_t start_offset;
+       off_t end_offset;
 
        wimlib_assert(image == WIMLIB_ALL_IMAGES ||
                        (wim_info != NULL && image >= 1 &&
@@ -1307,42 +1296,55 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        if (start_offset == -1)
                return WIMLIB_ERR_WRITE;
 
+       DEBUG("Writing XML data for image %d at offset %"PRIu64,
+             image, start_offset);
+
+       /* 2 bytes endianness marker for UTF-16LE.  This is _required_ for WIM
+        * XML data. */
+       if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF)) {
+               ERROR_WITH_ERRNO("Error writing XML data");
+               return WIMLIB_ERR_WRITE;
+       }
+
        /* The contents of the <TOTALBYTES> element in the XML data, under the
-        * <WIM> element not the <IMAGE> element, is (for non-spit WIMs) the
-        * size of the WIM file excluding the XML data and integrity table,
-        * which is the current offset, since the XML data goes at the end of
-        * the WIM file before the integrity table. */
-       if (total_bytes == 0) {
-               total_bytes = ftello(out);
-               if (total_bytes == (u64)-1)
-                       return WIMLIB_ERR_WRITE;
+        * <WIM> element (not the <IMAGE> element), is for non-split WIMs the
+        * size of the WIM file excluding the XML data and integrity table.
+        * This should be equal to the current position in the output stream,
+        * since the XML data and integrity table are the last elements of the
+        * WIM.
+        *
+        * For split WIMs, <TOTALBYTES> takes into account the entire WIM, not
+        * just the current part.  In that case, @total_bytes should be passed
+        * in to this function. */
+       if (total_bytes == 0)
+               total_bytes = start_offset;
+
+       xmlInitCharEncodingHandlers();
+
+       /* The encoding of the XML data must be UTF-16LE. */
+       encoding_handler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF16LE);
+       if (!encoding_handler) {
+               ERROR("Failed to get XML character encoding handler for UTF-16LE");
+               ret = WIMLIB_ERR_CHAR_CONVERSION;
+               goto out_cleanup_char_encoding_handlers;
        }
 
-       DEBUG("Creating XML buffer and text writer.");
-       buf = xmlBufferCreate();
-       if (!buf) {
-               ERROR("Failed to allocate XML buffer");
+       out_buffer = xmlOutputBufferCreateFile(out, encoding_handler);
+       if (!out_buffer) {
+               ERROR("Failed to allocate xmlOutputBuffer");
                ret = WIMLIB_ERR_NOMEM;
-               goto out;
+               goto out_cleanup_char_encoding_handlers;
        }
-       writer = xmlNewTextWriterMemory(buf, 0);
+
+       writer = xmlNewTextWriter(out_buffer);
        if (!writer) {
-               ERROR("Failed to allocate XML writer");
+               ERROR("Failed to allocate xmlTextWriter");
                ret = WIMLIB_ERR_NOMEM;
-               goto out_buffer_free;
+               goto out_output_buffer_close;
        }
 
-       /* XXX */
-       /* M$'s WIM files do not have XML declarations, so do not write one.
-        * I'm not sure how we can force the document to be written in UTF-16
-        * without calling xmlTextWriterStartDocument(), though, so currently it
-        * is composed in a buffer UTF-8, then converted to UTF-16. */
-#if 0
-       ret = xmlTextWriterStartDocument(writer, NULL, "UTF-16", NULL);
-       CHECK_RET;
-#endif
-
        DEBUG("Writing <WIM> element");
+
        ret = xmlTextWriterStartElement(writer, "WIM");
        CHECK_RET;
 
@@ -1351,11 +1353,16 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        CHECK_RET;
 
        if (wim_info != NULL) {
-               DEBUG("Writing %d <IMAGE> elements", (int)wim_info->num_images);
-               for (int i = 1; i <= (int)wim_info->num_images; i++) {
-                       if (image != WIMLIB_ALL_IMAGES && i != image)
-                               continue;
-                       DEBUG("Writing <IMAGE> element for image %d", i);
+               int first, last;
+               if (image == WIMLIB_ALL_IMAGES) {
+                       first = 1;
+                       last = wim_info->num_images;
+               } else {
+                       first = image;
+                       last = image;
+               }
+               DEBUG("Writing %d <IMAGE> elements", last - first + 1);
+               for (int i = first; i <= last; i++) {
                        ret = xml_write_image_info(writer, &wim_info->images[i - 1]);
                        CHECK_RET;
                }
@@ -1367,62 +1374,43 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        ret = xmlTextWriterEndDocument(writer);
        CHECK_RET;
 
+       DEBUG("Ended XML document");
+
+       /* Call xmlFreeTextWriter() before ftello() because the former will
+        * flush the file stream. */
        xmlFreeTextWriter(writer);
        writer = NULL;
-       DEBUG("Done composing XML document. Now converting to UTF-16 and "
-             "writing it to the output file.");
-
-       content = xmlBufferContent(buf);
-       len = xmlBufferLength(buf);
-
-       DEBUG("XML UTF-8 length = %zu", len);
-
-       utf16_str = utf8_to_utf16(content, len, &utf16_len);
-       if (!utf16_str) {
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_free_text_writer;
-       }
-
-       DEBUG("XML UTF-16 length = %zu", utf16_len);
-
-       if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF) ||
-               ((bytes_written = fwrite(utf16_str, 1, utf16_len, out))
-                               != utf16_len)) {
-               ERROR_WITH_ERRNO("Error writing XML data");
-               ret = WIMLIB_ERR_WRITE;
-               goto out_free_utf16_str;
-       }
-
-       DEBUG("Cleaning up.");
 
        end_offset = ftello(out);
        if (end_offset == -1) {
                ret = WIMLIB_ERR_WRITE;
-               goto out_free_utf16_str;
+       } else {
+               ret = 0;
+               out_res_entry->offset        = start_offset;
+               out_res_entry->size          = end_offset - start_offset;
+               out_res_entry->original_size = end_offset - start_offset;
+               out_res_entry->flags         = WIM_RESHDR_FLAG_METADATA;
        }
-
-       out_res_entry->offset        = start_offset;
-       out_res_entry->size          = end_offset - start_offset;
-       out_res_entry->original_size = end_offset - start_offset;
-       out_res_entry->flags         = WIM_RESHDR_FLAG_METADATA;
-       ret = 0;
-out_free_utf16_str:
-       FREE(utf16_str);
 out_free_text_writer:
+       /* xmlFreeTextWriter will free the attached xmlOutputBuffer. */
        xmlFreeTextWriter(writer);
-out_buffer_free:
-       xmlBufferFree(buf);
+       out_buffer = NULL;
+out_output_buffer_close:
+       if (out_buffer != NULL)
+               xmlOutputBufferClose(out_buffer);
+out_cleanup_char_encoding_handlers:
+       xmlCleanupCharEncodingHandlers();
 out:
+       if (ret == 0)
+               DEBUG("Successfully wrote XML data");
        return ret;
 }
 
 /* Returns the name of the specified image. */
 WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image)
 {
-       DEBUG("Getting the name of image %d", image);
        if (image < 1 || image > w->hdr.image_count)
                return NULL;
-
        return w->wim_info->images[image - 1].name;
 }
 
@@ -1430,34 +1418,27 @@ WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image)
 WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w,
                                                   int image)
 {
-       DEBUG("Getting the description of image %d", image);
        if (image < 1 || image > w->hdr.image_count)
                return NULL;
-
        return w->wim_info->images[image - 1].description;
 }
 
 /* Determines if an image name is already used by some image in the WIM. */
 WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name)
 {
-       int i;
-
-       DEBUG("Checking to see if the image name `%s' is already in use", name);
-       if (!name || !*name || !w->wim_info)
+       if (!name || !*name)
                return false;
-       for (i = 1; i <= w->wim_info->num_images; i++)
+       for (int i = 1; i <= w->hdr.image_count; i++)
                if (strcmp(w->wim_info->images[i - 1].name, name) == 0)
                        return true;
-
        return false;
 }
 
+/* Extracts the raw XML data to a file stream. */
 WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp)
 {
-       DEBUG("Extracting the XML data.");
        if (!w->xml_data)
                return WIMLIB_ERR_INVALID_PARAM;
-
        if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) !=
                        w->hdr.xml_res_entry.size) {
                ERROR_WITH_ERRNO("Failed to extract XML data");
@@ -1474,13 +1455,11 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name)
 
        DEBUG("Setting the name of image %d to %s", image, name);
 
-       if (!w)
-               return WIMLIB_ERR_INVALID_PARAM;
-
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");
                return WIMLIB_ERR_INVALID_PARAM;
        }
+
        if (image < 1 || image > w->hdr.image_count) {
                ERROR("%d is not a valid image", image);
                return WIMLIB_ERR_INVALID_IMAGE;
@@ -1497,10 +1476,9 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name)
        }
 
        p = STRDUP(name);
-       if (!p) {
-               ERROR("Out of memory");
+       if (!p)
                return WIMLIB_ERR_NOMEM;
-       }
+
        FREE(w->wim_info->images[image - 1].name);
        w->wim_info->images[image - 1].name = p;
        return 0;
@@ -1512,21 +1490,14 @@ WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image,
 {
        char *p;
 
-       DEBUG("Setting the description of image %d to %s", image, description);
-
-       if (!w)
-               return WIMLIB_ERR_INVALID_PARAM;
-
        if (image < 1 || image > w->hdr.image_count) {
                ERROR("%d is not a valid image", image);
                return WIMLIB_ERR_INVALID_IMAGE;
        }
        if (description) {
                p = STRDUP(description);
-               if (!p) {
-                       ERROR("Out of memory");
+               if (!p)
                        return WIMLIB_ERR_NOMEM;
-               }
        } else {
                p = NULL;
        }
@@ -1535,23 +1506,20 @@ WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image,
        return 0;
 }
 
+/* Set the <FLAGS> element of a WIM image */
 WIMLIBAPI int wimlib_set_image_flags(WIMStruct *w, int image,
                                     const char *flags)
 {
        char *p;
 
-       DEBUG("Setting the flags of image %d to %s", image, flags);
-
        if (image < 1 || image > w->hdr.image_count) {
                ERROR("%d is not a valid image", image);
                return WIMLIB_ERR_INVALID_IMAGE;
        }
        if (flags) {
                p = STRDUP(flags);
-               if (!p) {
-                       ERROR("Out of memory");
+               if (!p)
                        return WIMLIB_ERR_NOMEM;
-               }
        } else {
                p = NULL;
        }
index 5a87575..5eb24c9 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -6,7 +6,7 @@
 /* A struct wim_info structure corresponds to the entire XML data for a WIM file. */
 struct wim_info {
        u64 total_bytes;
-       u64 num_images;
+       int num_images;
        /* Array of `struct image_info's, one for each image in the WIM that is
         * mentioned in the XML data. */
        struct image_info *images;