]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Improve tstr <=> UTF-16LE conversions
[wimlib] / src / extract.c
index f1fcd0f86b5079b9ef020a03e35287c2edfbf831..a4029ec23f39c718497e57d992d6de752917a63f 100644 (file)
@@ -1273,14 +1273,23 @@ need_tmpfile_to_extract(struct wim_lookup_table_entry *lte,
 }
 
 static int
-begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
-                               bool is_partial_res,
-                               void *_ctx)
+begin_extract_stream(struct wim_lookup_table_entry *lte,
+                    u32 flags, void *_ctx)
 {
        struct apply_ctx *ctx = _ctx;
        int ret;
 
-       if (!need_tmpfile_to_extract(lte, is_partial_res)) {
+       if (flags & BEGIN_STREAM_FLAG_WHOLE_STREAM) {
+               DEBUG("Whole stream (size=%"PRIu64") will be read into memory",
+                     lte->size);
+               ctx->cur_stream = lte;
+               filedes_invalidate(&ctx->tmpfile_fd);
+               return 0;
+       }
+
+       if (!need_tmpfile_to_extract(lte,
+                                    (flags & BEGIN_STREAM_FLAG_PARTIAL_RESOURCE)))
+       {
                DEBUG("Temporary file not needed "
                      "for stream (size=%"PRIu64")", lte->size);
                ret = extract_stream_instances(lte, lte, ctx);
@@ -1295,14 +1304,42 @@ begin_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
 }
 
 static int
-end_extract_stream_to_tmpfile(struct wim_lookup_table_entry *lte,
-                             int status, void *_ctx)
+extract_chunk(const void *chunk, size_t size, void *_ctx)
+{
+       struct apply_ctx *ctx = _ctx;
+       int ret;
+
+       if (filedes_valid(&ctx->tmpfile_fd)) {
+               ret = full_write(&ctx->tmpfile_fd, chunk, size);
+               if (ret)
+                       ERROR_WITH_ERRNO("Error writing to file descriptor");
+       } else {
+               struct wim_lookup_table_entry lte_override;
+
+               memcpy(&lte_override, ctx->cur_stream,
+                      sizeof(struct wim_lookup_table_entry));
+
+               lte_override.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+               lte_override.size = size;
+               lte_override.attached_buffer = (void *)chunk;
+
+               ret = extract_stream_instances(ctx->cur_stream, &lte_override, ctx);
+       }
+       return ret;
+}
+
+static int
+end_extract_stream(struct wim_lookup_table_entry *lte,
+                  int status, void *_ctx)
 {
        struct apply_ctx *ctx = _ctx;
        struct wim_lookup_table_entry lte_override;
        int ret;
        int errno_save = errno;
 
+       if (!filedes_valid(&ctx->tmpfile_fd))
+               return status;
+
        ret = filedes_close(&ctx->tmpfile_fd);
 
        if (status) {
@@ -1342,11 +1379,11 @@ static int
 extract_stream_list(struct apply_ctx *ctx)
 {
        struct read_stream_list_callbacks cbs = {
-               .begin_stream           = begin_extract_stream_to_tmpfile,
+               .begin_stream           = begin_extract_stream,
                .begin_stream_ctx       = ctx,
-               .consume_chunk          = extract_chunk_to_fd,
-               .consume_chunk_ctx      = &ctx->tmpfile_fd,
-               .end_stream             = end_extract_stream_to_tmpfile,
+               .consume_chunk          = extract_chunk,
+               .consume_chunk_ctx      = ctx,
+               .end_stream             = end_extract_stream,
                .end_stream_ctx         = ctx,
        };
        return read_stream_list(&ctx->stream_list,
@@ -1821,16 +1858,12 @@ dentry_calculate_extraction_name(struct wim_dentry *dentry,
        }
 
        if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) {
-#if TCHAR_IS_UTF16LE
-               dentry->extraction_name = dentry->file_name;
-               dentry->extraction_name_nchars = dentry->file_name_nbytes / 2;
-               return 0;
-#else
-               return utf16le_to_tstr(dentry->file_name,
+               ret = utf16le_get_tstr(dentry->file_name,
                                       dentry->file_name_nbytes,
-                                      &dentry->extraction_name,
+                                      (const tchar **)&dentry->extraction_name,
                                       &dentry->extraction_name_nchars);
-#endif
+               dentry->extraction_name_nchars /= sizeof(tchar);
+               return ret;
        } else {
                if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES)
                {
@@ -1854,18 +1887,17 @@ out_replace:
                memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes);
                file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true);
 
-               tchar *tchar_name;
+               const tchar *tchar_name;
                size_t tchar_nchars;
-       #if TCHAR_IS_UTF16LE
-               tchar_name = utf16_name_copy;
-               tchar_nchars = dentry->file_name_nbytes / 2;
-       #else
-               ret = utf16le_to_tstr(utf16_name_copy,
-                                     dentry->file_name_nbytes,
-                                     &tchar_name, &tchar_nchars);
+
+               ret = utf16le_get_tstr(utf16_name_copy,
+                                      dentry->file_name_nbytes,
+                                      &tchar_name, &tchar_nchars);
                if (ret)
                        return ret;
-       #endif
+
+               tchar_nchars /= sizeof(tchar);
+
                size_t fixed_name_num_chars = tchar_nchars;
                tchar fixed_name[tchar_nchars + 50];
 
@@ -1873,9 +1905,9 @@ out_replace:
                fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars,
                                                 T(" (invalid filename #%lu)"),
                                                 ++ctx->invalid_sequence);
-       #if !TCHAR_IS_UTF16LE
-               FREE(tchar_name);
-       #endif
+
+               utf16le_put_tstr(tchar_name);
+
                dentry->extraction_name = memdup(fixed_name,
                                                 2 * fixed_name_num_chars + 2);
                if (!dentry->extraction_name)