1 /* 2 * Copyright (C) 2012 Google Inc. and others 3 * 4 * This program and the accompanying materials are made available under the 5 * terms of the Eclipse Distribution License v. 1.0 which is available at 6 * https://www.eclipse.org/org/documents/edl-v10.php. 7 * 8 * SPDX-License-Identifier: BSD-3-Clause 9 */ 10 package org.eclipse.jgit.archive; 11 12 import java.io.IOException; 13 import java.io.OutputStream; 14 import java.text.MessageFormat; 15 import java.util.Arrays; 16 import java.util.Collections; 17 import java.util.List; 18 import java.util.Map; 19 20 import org.apache.commons.compress.archivers.ArchiveOutputStream; 21 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 22 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; 23 import org.eclipse.jgit.api.ArchiveCommand; 24 import org.eclipse.jgit.archive.internal.ArchiveText; 25 import org.eclipse.jgit.lib.FileMode; 26 import org.eclipse.jgit.lib.ObjectId; 27 import org.eclipse.jgit.lib.ObjectLoader; 28 import org.eclipse.jgit.revwalk.RevCommit; 29 30 /** 31 * PKWARE's ZIP format. 32 */ 33 public final class ZipFormat extends BaseFormat implements 34 ArchiveCommand.Format<ArchiveOutputStream> { 35 private static final List<String> SUFFIXES = Collections 36 .unmodifiableList(Arrays.asList(".zip")); //$NON-NLS-1$ 37 38 /** {@inheritDoc} */ 39 @Override createArchiveOutputStream(OutputStream s)40 public ArchiveOutputStream createArchiveOutputStream(OutputStream s) 41 throws IOException { 42 return createArchiveOutputStream(s, 43 Collections.<String, Object> emptyMap()); 44 } 45 46 /** {@inheritDoc} */ 47 @Override createArchiveOutputStream(OutputStream s, Map<String, Object> o)48 public ArchiveOutputStream createArchiveOutputStream(OutputStream s, 49 Map<String, Object> o) throws IOException { 50 ZipArchiveOutputStream out = new ZipArchiveOutputStream(s); 51 int compressionLevel = getCompressionLevel(o); 52 if (compressionLevel != -1) { 53 out.setLevel(compressionLevel); 54 } 55 return applyFormatOptions(out, o); 56 } 57 58 /** {@inheritDoc} */ 59 @Override putEntry(ArchiveOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader)60 public void putEntry(ArchiveOutputStream out, 61 ObjectId tree, String path, FileMode mode, ObjectLoader loader) 62 throws IOException { 63 // ZipArchiveEntry detects directories by checking 64 // for '/' at the end of the filename. 65 if (path.endsWith("/") && mode != FileMode.TREE) //$NON-NLS-1$ 66 throw new IllegalArgumentException(MessageFormat.format( 67 ArchiveText.get().pathDoesNotMatchMode, path, mode)); 68 if (!path.endsWith("/") && mode == FileMode.TREE) //$NON-NLS-1$ 69 path = path + "/"; //$NON-NLS-1$ 70 71 final ZipArchiveEntry entry = new ZipArchiveEntry(path); 72 73 if (tree instanceof RevCommit) { 74 long t = ((RevCommit) tree).getCommitTime() * 1000L; 75 entry.setTime(t); 76 } 77 78 if (mode == FileMode.TREE) { 79 out.putArchiveEntry(entry); 80 out.closeArchiveEntry(); 81 return; 82 } 83 84 if (mode == FileMode.REGULAR_FILE) { 85 // ok 86 } else if (mode == FileMode.EXECUTABLE_FILE 87 || mode == FileMode.SYMLINK) { 88 entry.setUnixMode(mode.getBits()); 89 } else { 90 // Unsupported mode (e.g., GITLINK). 91 throw new IllegalArgumentException(MessageFormat.format( 92 ArchiveText.get().unsupportedMode, mode)); 93 } 94 entry.setSize(loader.getSize()); 95 out.putArchiveEntry(entry); 96 loader.copyTo(out); 97 out.closeArchiveEntry(); 98 } 99 100 /** {@inheritDoc} */ 101 @Override suffixes()102 public Iterable<String> suffixes() { 103 return SUFFIXES; 104 } 105 106 /** {@inheritDoc} */ 107 @Override equals(Object other)108 public boolean equals(Object other) { 109 return (other instanceof ZipFormat); 110 } 111 112 /** {@inheritDoc} */ 113 @Override hashCode()114 public int hashCode() { 115 return getClass().hashCode(); 116 } 117 } 118