001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.compress.archivers; 019 020import java.io.BufferedInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.nio.file.Files; 024import java.nio.file.Path; 025import java.nio.file.Paths; 026import java.util.Enumeration; 027import java.util.Locale; 028import java.util.Objects; 029 030import org.apache.commons.compress.archivers.sevenz.SevenZFile; 031import org.apache.commons.compress.archivers.tar.TarFile; 032import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 033import org.apache.commons.compress.archivers.zip.ZipFile; 034 035/** 036 * Simple command line application that lists the contents of an archive. 037 * 038 * <p> 039 * The name of the archive must be given as a command line argument. 040 * </p> 041 * <p> 042 * The optional second argument defines the archive type, in case the format is not recognized. 043 * </p> 044 * 045 * @since 1.1 046 */ 047public final class Lister { 048 049 private static final ArchiveStreamFactory FACTORY = ArchiveStreamFactory.DEFAULT; 050 051 private static <T extends ArchiveInputStream<? extends E>, E extends ArchiveEntry> T createArchiveInputStream(final String[] args, 052 final InputStream inputStream) throws ArchiveException { 053 if (args.length > 1) { 054 return FACTORY.createArchiveInputStream(args[1], inputStream); 055 } 056 return FACTORY.createArchiveInputStream(inputStream); 057 } 058 059 private static String detectFormat(final Path file) throws ArchiveException, IOException { 060 try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file))) { 061 return ArchiveStreamFactory.detect(inputStream); 062 } 063 } 064 065 /** 066 * Runs this class from the command line. 067 * <p> 068 * The name of the archive must be given as a command line argument. 069 * </p> 070 * <p> 071 * The optional second argument defines the archive type, in case the format is not recognized. 072 * </p> 073 * 074 * @param args name of the archive and optional argument archive type. 075 * @throws ArchiveException Archiver related Exception. 076 * @throws IOException an I/O exception. 077 */ 078 public static void main(final String... args) throws ArchiveException, IOException { 079 if (args == null || args.length == 0) { 080 usage(); 081 return; 082 } 083 new Lister(false, args).go(); 084 } 085 086 private static void usage() { 087 System.err.println("Parameters: archive-name [archive-type]\n"); 088 System.err.println("The magic archive-type 'zipfile' prefers ZipFile over ZipArchiveInputStream"); 089 System.err.println("The magic archive-type 'tarfile' prefers TarFile over TarArchiveInputStream"); 090 } 091 092 private final boolean quiet; 093 094 private final String[] args; 095 096 /** 097 * Constructs a new instance. 098 * 099 * @deprecated No replacement. 100 */ 101 @Deprecated 102 public Lister() { 103 this(false, ""); 104 } 105 106 Lister(final boolean quiet, final String... args) { 107 this.quiet = quiet; 108 this.args = args.clone(); 109 Objects.requireNonNull(args[0], "args[0]"); 110 } 111 112 void go() throws ArchiveException, IOException { 113 list(Paths.get(args[0]), args); 114 } 115 116 private void list(final Path file, final String... args) throws ArchiveException, IOException { 117 println("Analyzing " + file); 118 if (!Files.isRegularFile(file)) { 119 System.err.println(file + " doesn't exist or is a directory"); 120 } 121 final String format = (args.length > 1 ? args[1] : detectFormat(file)).toLowerCase(Locale.ROOT); 122 println("Detected format " + format); 123 switch (format) { 124 case ArchiveStreamFactory.SEVEN_Z: 125 list7z(file); 126 break; 127 case ArchiveStreamFactory.ZIP: 128 listZipUsingZipFile(file); 129 break; 130 case ArchiveStreamFactory.TAR: 131 listZipUsingTarFile(file); 132 break; 133 default: 134 listStream(file, args); 135 } 136 } 137 138 private void list7z(final Path file) throws IOException { 139 try (SevenZFile sevenZFile = SevenZFile.builder().setPath(file).get()) { 140 println("Created " + sevenZFile); 141 ArchiveEntry entry; 142 while ((entry = sevenZFile.getNextEntry()) != null) { 143 println(entry.getName() == null ? sevenZFile.getDefaultName() + " (entry name was null)" : entry.getName()); 144 } 145 } 146 } 147 148 private void listStream(final Path file, final String[] args) throws ArchiveException, IOException { 149 try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file)); 150 ArchiveInputStream<?> archiveInputStream = createArchiveInputStream(args, inputStream)) { 151 println("Created " + archiveInputStream.toString()); 152 ArchiveEntry entry; 153 while ((entry = archiveInputStream.getNextEntry()) != null) { 154 println(entry); 155 } 156 } 157 } 158 159 private void listZipUsingTarFile(final Path file) throws IOException { 160 try (TarFile tarFile = new TarFile(file)) { 161 println("Created " + tarFile); 162 tarFile.getEntries().forEach(this::println); 163 } 164 } 165 166 private void listZipUsingZipFile(final Path file) throws IOException { 167 try (ZipFile zipFile = ZipFile.builder().setPath(file).get()) { 168 println("Created " + zipFile); 169 for (final Enumeration<ZipArchiveEntry> en = zipFile.getEntries(); en.hasMoreElements();) { 170 println(en.nextElement()); 171 } 172 } 173 } 174 175 private void println(final ArchiveEntry entry) { 176 println(entry.getName()); 177 } 178 179 private void println(final String line) { 180 if (!quiet) { 181 System.out.println(line); 182 } 183 } 184 185}