TgzArchiveWrapper.java

/*
 * Copyright © 2024-2025 The CTAN Team and individual authors
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.services.upload.util.archive;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.NonNull;

/**
 * The class <code>TgzArchiveWrapper</code> contains an adaptor for a TGZ
 * archive.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public class TgzArchiveWrapper implements Archive {

    /**
     * The class <code>TgzEntryWrapper</code> contains the wrapper for an entry.
     *
     */
    public static class TgzEntryWrapper implements Entry {

        /**
         * The field <code>entry</code> contains the wrapped entry.
         */
        private TarArchiveEntry entry;

        /**
         * This is the constructor for <code>ZipEntry</code>.
         *
         * @param entry the wrapped entry
         */
        @SuppressFBWarnings(value = "EI_EXPOSE_REP2")
        public TgzEntryWrapper(TarArchiveEntry entry) {

            this.entry = entry;
        }

        /**
         * {@inheritDoc}
         *
         * @see org.ctan.site.services.upload.util.archive.Archive.Entry#getName()
         */
        @Override
        public String getName() {

            return entry.getName();
        }

        /**
         * {@inheritDoc}
         *
         * @see org.ctan.site.services.upload.util.archive.Archive.Entry#isDirectory()
         */
        @Override
        public boolean isDirectory() {

            return entry.isDirectory();
        }
    }

    /**
     * The field <code>stream</code> contains the wrapped stream.
     */
    private TarArchiveInputStream stream;

    /**
     * The field <code>name</code> contains the file name.
     */
    private String name;

    /**
     * This is the constructor for <code>ZipArchive</code>.
     *
     * @param in the wrapped input stream
     * @param name the file name
     * @throws IOException in case of an I/O error
     */
    @SuppressFBWarnings(value = {"CT_CONSTRUCTOR_THROW", "EI_EXPOSE_REP2"})
    public TgzArchiveWrapper(String name, @NonNull InputStream in)
        throws IOException {

        this.name = name;
        this.stream = new TarArchiveInputStream(new GZIPInputStream(in));
    }

    /**
     * {@inheritDoc}
     *
     * @see org.ctan.site.services.upload.util.archive.Archive#close()
     */
    @Override
    public void close() throws IOException {

        stream.close();
    }

    /**
     * {@inheritDoc}
     *
     * @see org.ctan.site.services.upload.util.archive.Archive#closeEntry()
     */
    @Override
    public void closeEntry() {

    }

    /**
     * {@inheritDoc}
     *
     * @see org.ctan.site.services.upload.util.archive.Archive#getName()
     */
    @Override
    public String getName() {

        return name;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.ctan.site.services.upload.util.archive.Archive#getNextEntry()
     */
    @Override
    public Entry getNextEntry() throws IOException {

        TarArchiveEntry nextEntry = stream.getNextEntry();

        return nextEntry != null
            ? new TgzEntryWrapper(stream.getNextEntry())
            : null;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.ctan.site.services.upload.util.archive.Archive#getStream()
     */
    @Override
    @SuppressFBWarnings(value = "EI_EXPOSE_REP")
    public InputStream getStream() {

        return stream;
    }
}