Subject: Re: bug#67926: 29.1; fail to extract ZIP subfile named with [...]

From: Eli Zaretskii <[email-masked]>
Date: Tue, 26 Dec 2023 19:25:39 +0200

> From: [email-masked]
> Cc: [email-masked]
> Date: Tue, 26 Dec 2023 23:51:01 +0900
> 
> Eli Zaretskii <[email-masked]> writes:
> >> This is because 'unzip.exe' treats subfilename arguments containing
> >> '[...]' as subfilename patterns. This does not occur with '7z.exe'.
> >
> > Is there any way of making 'unzip' extract file[abc].txt by name,  by
> > some kind of escaping or protecting the [...] wildcard from expansion?
> > If there is such a way, we could try using it (maybe); if there's no
> > such way, I will tag this bug "wontfix", since it isn't a problem with
> > Emacs, but with the Windows build of 'unzip'.
> 
> There is a tricky way to specify "file[[]abc].txt".

That could be a good solution if it works reliably.

> I think that avoiding the use of unzip.exe/zip.exe solves problems about
> directory names, archive names, subfile names.
> Replacing #'archive-zip-extract with the form below,
> ZIP subfiles can be extracted without unzip.exe.
> 
> (defun archive-zip-extract (archive name)
>   (let* ((desc archive-subfile-mode)
>          (buf (current-buffer))
>          (bufname (buffer-file-name)))
>     (set-buffer archive-superior-buffer)
>     (save-restriction
>       (widen)
>       (let* ((file-beg archive-proper-file-start)
>              (p0 (+ file-beg (archive--file-desc-pos desc)))
>              (p  (+ file-beg (archive-l-e (+ p0 42) 4)))
>              (bitflags (archive-l-e (+ p  6) 2))
>              (method   (archive-l-e (+ p  8) 2))
>              (compsize (archive-l-e (+ p0 20) 4))
>              (fn-len   (archive-l-e (+ p 26) 2))
>              (ex-len   (archive-l-e (+ p 28) 2))
>              (data-beg (+ p 30 fn-len ex-len))
>              (data-end (+ data-beg compsize))
>              (coding-system-for-read  'no-conversion)
>              (coding-system-for-write 'no-conversion)
>              (default-directory temporary-file-directory))
>         (cond ((/= 0 (logand bitflags 1))
>                (message "Subfile is encrypted"))
>               ((= method 0)
>                (with-current-buffer buf
>                  (insert-buffer-substring archive-superior-buffer
>                                           data-beg data-end)))
>               ((eq method 8)
>                (let ((crc-32    (buffer-substring (+ p0 16) (+ p0 20)))
>                      (orig-size (buffer-substring (+ p0 24) (+ p0 28)))
>                      (proc (start-process "gzip" buf "gzip" "-cd"))
>                      (header "\x1f\x8b\x08\0\0\0\0\0\0\0"))
>                  (set-process-sentinel proc #'ignore)
>                  (process-send-string proc header)
>                  (process-send-region proc data-beg data-end)
>                  (process-send-string proc crc-32)
>                  (process-send-string proc orig-size)
>                  (process-send-eof proc)
>                  (accept-process-output proc nil nil t)
>                  (delete-process proc)))
>               ((eq method 12)
>                (call-process-region data-beg data-end
>                                     "bzip2" nil buf nil "-cd"))
>               (t (message "Unknown compression method")))))
>     (set-buffer buf)))

Thanks, but I don't think it's a good idea.  There are more
compression methods than just those 3, and some of them aren't
documented.  unzip.exe itself supports 17 methods.  So I'd rather stay
with unzip.exe than invent our own wheel.