#  File src/library/utils/R/zip.R
#  Part of the R package, https://www.R-project.org
#
#  Copyright (C) 1995-2023 The R Core Team
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  A copy of the GNU General Public License is available at
#  https://www.R-project.org/Licenses/

unzip <-
    function(zipfile, files = NULL, list = FALSE, overwrite = TRUE,
             junkpaths = FALSE, exdir = ".", unzip = "internal",
             setTimes = FALSE)
{
    if(identical(unzip, "internal")) {
        if(!list && !missing(exdir))
            dir.create(exdir, showWarnings = FALSE, recursive = TRUE)
        res <- .External(C_unzip, zipfile, files, exdir, list, overwrite,
                         junkpaths, setTimes)
        if(list) {
            dates <- as.POSIXct(res[[3]], "%Y-%m-%d %H:%M",  tz="UTC")
            data.frame(Name = res[[1]], Length = res[[2]], Date = dates,
                       stringsAsFactors = FALSE)
        } else invisible(attr(res, "extracted"))
    } else {
        WINDOWS <- .Platform$OS.type == "windows"
        if(!is.character(unzip) || length(unzip) != 1L || !nzchar(unzip))
            stop(gettextf("'%s' must be a non-empty character string", "unzip"),
                 domain = NA)
        if (list) {
            ## -q to suppress per-file and per-archive comments (since 5.52)
            ## it also suppresses the first line "Archive: filename"
            res <- if (WINDOWS)
                    system2(unzip, c("-ql", shQuote(zipfile)), stdout = TRUE)
                else
                    system2(unzip, c("-ql", shQuote(zipfile)), stdout = TRUE,
                            env = c("TZ=UTC"))
            l <- length(res)
            res2 <- res[-c(2, l-1, l)]

            ## this allows space in file name, but it would break with
            ## double quotes (though those are discouraged both by Windows
            ## documentation and POSIX)
            res3 <- gsub(" *([^ ]+) +([^ ]+) +([^ ]+) +(.*)",
                         "\\1 \\2 \\3 \"\\4\"", res2)
            con <- textConnection(res3); on.exit(close(con))
            z <- read.table(con, header=TRUE, as.is=TRUE)
            dt <- paste(z$Date, z$Time)
            ## Unzip 6.00 always uses 4-digits years, but any order is
            ## possible and the separator could be - or / (depending
            ## on the locale on Windows).
            ## Unzip 5.52 uses 2-digit years, but default to "%m-%d-%y" on
            ## most platforms (but is locale-dependent on Windows).
            formats <-
                if (max(nchar(z$Date) > 8))
                    c("%Y-%m-%d", "%d-%m-%Y", "%m-%d-%Y") else
                    ## At this point we are guessing: there is no way
                    ## to know what "08-09-10" means.  Take the most common
                    ## default first.
                    c("%m-%d-%y", "%d-%m-%y", "%y-%m-%d")
            slash <- any(grepl("/", z$Date))
            if (slash) formats <- gsub("-", "/", formats, fixed=TRUE)
            formats <- paste(formats, "%H:%M")
            for (f in formats) {
                zz <- as.POSIXct(dt, tz="UTC", format = f)
                if (all(!is.na(zz))) break
            }
            z[, "Date"] <- zz
            z[c("Name", "Length", "Date")]
        } else {
            ## -n -o -q -j are supported in Unzip 5.52 and 6.00
            args <- character()
            if (junkpaths) args <- c(args, "-j")
            if (overwrite)
                args <- c(args, "-oq", shQuote(zipfile))
            else
                args <- c(args, "-nq", shQuote(zipfile))
            if (length(files)) args <- c(args, shQuote(files))
            if (exdir != ".") args <- c(args, "-d", shQuote(exdir))
            ## there is an unzip clone about that does not respect -q
            if (WINDOWS)
                system2(unzip, args, stdout = NULL, stderr = NULL,
                        invisible = TRUE)
            else
                system2(unzip, args, stdout = NULL, stderr = NULL)
            invisible(NULL)
        }
    }
}

zip <- function(zipfile, files, flags = "-r9X", extras = "",
                zip = Sys.getenv("R_ZIPCMD", "zip"))
{
    if (missing(flags) && (!is.character(files) || !length(files)))
        stop("'files' must be a character vector specifying one or more filepaths")
    if(!is.character(zip) || length(zip) != 1L || !nzchar(zip))
        stop(gettextf("'%s' must be a non-empty character string", "zip"),
             domain = NA)
    args <- c(flags, shQuote(path.expand(zipfile)),
              shQuote(files), extras)
    if (sum(nchar(c(args, Sys.getenv()))) + length(args) > 8000) {
        # -@ is supported in Info-ZIP from version 2.3 (like -X), but not in
        # old Mac OS builds (MACOS macro), so better not rely on it for
        # common use
        #
        # 8191 is the maximum command line length on Windows (since 2000/NT)
        # and 8096 is the internal buffer size used by system() on systems
        # without readline
        args <- c(flags, "-@", shQuote(path.expand(zipfile)), extras)
        input <- files
    } else input <- NULL

    if (.Platform$OS.type == "windows")
        invisible(system2(zip, args, input = input, invisible = TRUE))
    else invisible(system2(zip, args, input = input))
}

