156276d05SJonathan Nieder /* 25c5f7c6bSMatthias Sohn * Copyright (C) 2012 Google Inc. and others 356276d05SJonathan Nieder * 45c5f7c6bSMatthias Sohn * This program and the accompanying materials are made available under the 55c5f7c6bSMatthias Sohn * terms of the Eclipse Distribution License v. 1.0 which is available at 65c5f7c6bSMatthias Sohn * https://www.eclipse.org/org/documents/edl-v10.php. 756276d05SJonathan Nieder * 85c5f7c6bSMatthias Sohn * SPDX-License-Identifier: BSD-3-Clause 956276d05SJonathan Nieder */ 1056276d05SJonathan Nieder package org.eclipse.jgit.archive; 1156276d05SJonathan Nieder 1256276d05SJonathan Nieder import java.io.IOException; 1356276d05SJonathan Nieder import java.io.OutputStream; 142ecc27dbSJonathan Nieder import java.text.MessageFormat; 1556cb2d92SJonathan Nieder import java.util.Arrays; 1656cb2d92SJonathan Nieder import java.util.Collections; 1756cb2d92SJonathan Nieder import java.util.List; 18c0c4c6f0SDavid Ostrovsky import java.util.Map; 1956276d05SJonathan Nieder 2056276d05SJonathan Nieder import org.apache.commons.compress.archivers.ArchiveOutputStream; 2156276d05SJonathan Nieder import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 2256276d05SJonathan Nieder import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; 2356276d05SJonathan Nieder import org.eclipse.jgit.api.ArchiveCommand; 242ecc27dbSJonathan Nieder import org.eclipse.jgit.archive.internal.ArchiveText; 2556276d05SJonathan Nieder import org.eclipse.jgit.lib.FileMode; 261448ec37SNaoki Takezoe import org.eclipse.jgit.lib.ObjectId; 2756276d05SJonathan Nieder import org.eclipse.jgit.lib.ObjectLoader; 281448ec37SNaoki Takezoe import org.eclipse.jgit.revwalk.RevCommit; 2956276d05SJonathan Nieder 30659cadf0SJonathan Nieder /** 31659cadf0SJonathan Nieder * PKWARE's ZIP format. 32659cadf0SJonathan Nieder */ 33c0c4c6f0SDavid Ostrovsky public final class ZipFormat extends BaseFormat implements 34c0c4c6f0SDavid Ostrovsky ArchiveCommand.Format<ArchiveOutputStream> { 354ceb25b6SRobin Rosenberg private static final List<String> SUFFIXES = Collections 364ceb25b6SRobin Rosenberg .unmodifiableList(Arrays.asList(".zip")); //$NON-NLS-1$ 3756cb2d92SJonathan Nieder 3832022e97SMatthias Sohn /** {@inheritDoc} */ 3930628e3bSMatthias Sohn @Override createArchiveOutputStream(OutputStream s)40c0c4c6f0SDavid Ostrovsky public ArchiveOutputStream createArchiveOutputStream(OutputStream s) 41c0c4c6f0SDavid Ostrovsky throws IOException { 42c0c4c6f0SDavid Ostrovsky return createArchiveOutputStream(s, 43c0c4c6f0SDavid Ostrovsky Collections.<String, Object> emptyMap()); 44c0c4c6f0SDavid Ostrovsky } 45c0c4c6f0SDavid Ostrovsky 4632022e97SMatthias Sohn /** {@inheritDoc} */ 4730628e3bSMatthias Sohn @Override createArchiveOutputStream(OutputStream s, Map<String, Object> o)48c0c4c6f0SDavid Ostrovsky public ArchiveOutputStream createArchiveOutputStream(OutputStream s, 49c0c4c6f0SDavid Ostrovsky Map<String, Object> o) throws IOException { 50*6f82690aSYoussef Elghareeb ZipArchiveOutputStream out = new ZipArchiveOutputStream(s); 51*6f82690aSYoussef Elghareeb int compressionLevel = getCompressionLevel(o); 52*6f82690aSYoussef Elghareeb if (compressionLevel != -1) { 53*6f82690aSYoussef Elghareeb out.setLevel(compressionLevel); 54*6f82690aSYoussef Elghareeb } 55*6f82690aSYoussef Elghareeb return applyFormatOptions(out, o); 5656276d05SJonathan Nieder } 5756276d05SJonathan Nieder 5832022e97SMatthias Sohn /** {@inheritDoc} */ 591448ec37SNaoki Takezoe @Override putEntry(ArchiveOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader)601448ec37SNaoki Takezoe public void putEntry(ArchiveOutputStream out, 611448ec37SNaoki Takezoe ObjectId tree, String path, FileMode mode, ObjectLoader loader) 621448ec37SNaoki Takezoe throws IOException { 632ecc27dbSJonathan Nieder // ZipArchiveEntry detects directories by checking 642ecc27dbSJonathan Nieder // for '/' at the end of the filename. 650bc98f17SRobin Rosenberg if (path.endsWith("/") && mode != FileMode.TREE) //$NON-NLS-1$ 662ecc27dbSJonathan Nieder throw new IllegalArgumentException(MessageFormat.format( 672ecc27dbSJonathan Nieder ArchiveText.get().pathDoesNotMatchMode, path, mode)); 680bc98f17SRobin Rosenberg if (!path.endsWith("/") && mode == FileMode.TREE) //$NON-NLS-1$ 690bc98f17SRobin Rosenberg path = path + "/"; //$NON-NLS-1$ 702ecc27dbSJonathan Nieder 7156276d05SJonathan Nieder final ZipArchiveEntry entry = new ZipArchiveEntry(path); 721448ec37SNaoki Takezoe 731448ec37SNaoki Takezoe if (tree instanceof RevCommit) { 74ff6e6c22SShawn Pearce long t = ((RevCommit) tree).getCommitTime() * 1000L; 75ff6e6c22SShawn Pearce entry.setTime(t); 761448ec37SNaoki Takezoe } 771448ec37SNaoki Takezoe 782ecc27dbSJonathan Nieder if (mode == FileMode.TREE) { 792ecc27dbSJonathan Nieder out.putArchiveEntry(entry); 802ecc27dbSJonathan Nieder out.closeArchiveEntry(); 812ecc27dbSJonathan Nieder return; 822ecc27dbSJonathan Nieder } 8356276d05SJonathan Nieder 8456276d05SJonathan Nieder if (mode == FileMode.REGULAR_FILE) { 8556276d05SJonathan Nieder // ok 8656276d05SJonathan Nieder } else if (mode == FileMode.EXECUTABLE_FILE 8756276d05SJonathan Nieder || mode == FileMode.SYMLINK) { 8856276d05SJonathan Nieder entry.setUnixMode(mode.getBits()); 8956276d05SJonathan Nieder } else { 902ecc27dbSJonathan Nieder // Unsupported mode (e.g., GITLINK). 912ecc27dbSJonathan Nieder throw new IllegalArgumentException(MessageFormat.format( 922ecc27dbSJonathan Nieder ArchiveText.get().unsupportedMode, mode)); 9356276d05SJonathan Nieder } 9456276d05SJonathan Nieder entry.setSize(loader.getSize()); 9556276d05SJonathan Nieder out.putArchiveEntry(entry); 9656276d05SJonathan Nieder loader.copyTo(out); 9756276d05SJonathan Nieder out.closeArchiveEntry(); 9856276d05SJonathan Nieder } 9956cb2d92SJonathan Nieder 10032022e97SMatthias Sohn /** {@inheritDoc} */ 10130628e3bSMatthias Sohn @Override suffixes()10256cb2d92SJonathan Nieder public Iterable<String> suffixes() { 10356cb2d92SJonathan Nieder return SUFFIXES; 10456cb2d92SJonathan Nieder } 1050a14909bSJonathan Nieder 10632022e97SMatthias Sohn /** {@inheritDoc} */ 1070a14909bSJonathan Nieder @Override equals(Object other)1080a14909bSJonathan Nieder public boolean equals(Object other) { 1090a14909bSJonathan Nieder return (other instanceof ZipFormat); 1100a14909bSJonathan Nieder } 1110a14909bSJonathan Nieder 11232022e97SMatthias Sohn /** {@inheritDoc} */ 1130a14909bSJonathan Nieder @Override hashCode()1140a14909bSJonathan Nieder public int hashCode() { 1150a14909bSJonathan Nieder return getClass().hashCode(); 1160a14909bSJonathan Nieder } 11756276d05SJonathan Nieder } 118