Skip to content

Commit 6412280

Browse files
#89 Add file or folder to specific path in zip
1 parent 38f8d50 commit 6412280

14 files changed

+233
-75
lines changed

src/main/java/ru/olegcherednik/zip4jvm/ZipFile.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
3030
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
3131
import ru.olegcherednik.zip4jvm.utils.EmptyInputStreamSupplier;
32-
import ru.olegcherednik.zip4jvm.utils.PathUtils;
3332
import ru.olegcherednik.zip4jvm.utils.quitely.Quietly;
3433
import ru.olegcherednik.zip4jvm.utils.quitely.functions.InputStreamSupplier;
3534

@@ -125,11 +124,11 @@ public InputStream getInputStream() {
125124

126125
public interface Writer extends Closeable {
127126

128-
default void add(Path path) {
129-
add(path, PathUtils.getName(path));
130-
}
127+
void add(Path path);
128+
129+
void addWithRename(Path path, String name);
131130

132-
void add(Path path, String name);
131+
void addWithMove(Path path, String dir);
133132

134133
void add(ZipFile.Entry entry);
135134

src/main/java/ru/olegcherednik/zip4jvm/ZipIt.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
2323
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettingsProvider;
2424
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
25-
import ru.olegcherednik.zip4jvm.utils.ValidationUtils;
2625

2726
import lombok.AccessLevel;
2827
import lombok.RequiredArgsConstructor;
@@ -128,7 +127,7 @@ public void add(Collection<Path> paths) throws IOException {
128127
if (CollectionUtils.isEmpty(paths))
129128
return;
130129

131-
paths.forEach(ValidationUtils::requireExists);
130+
requireExists(paths);
132131

133132
// TODO check that path != zip
134133
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
@@ -137,6 +136,28 @@ public void add(Collection<Path> paths) throws IOException {
137136
}
138137
}
139138

139+
/**
140+
* Add regular file or directory (keeping initial structure) to the new or existed zip archive under give
141+
* {@code name}.<br>
142+
* In case given {@code path} is a directory (or symlink to directory), then this directory will be renamed.<br>
143+
* In case given {@code path} is a regular file (or symlink to the file), then this file will be renamed.
144+
*
145+
* @param path path to the regular file or directory
146+
* @param name not {@literal null} name to be used for the {@code path}
147+
* @throws IOException in case of any problem with file access
148+
*/
149+
public void addWithRename(Path path, String name) throws IOException {
150+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
151+
zipFile.addWithRename(path, name);
152+
}
153+
}
154+
155+
public void addWithMove(Path path, String dir) throws IOException {
156+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
157+
zipFile.addWithMove(path, dir);
158+
}
159+
}
160+
140161
/**
141162
* Creates instance of zip file stream. It could be used to add multiple entries to the zip archive. It should be
142163
* correctly closed to flush all data.

src/main/java/ru/olegcherednik/zip4jvm/model/settings/ZipEntrySettings.java

+25
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ public static Builder builder() {
5454
return new Builder();
5555
}
5656

57+
public static ZipEntrySettings of(Compression compression) {
58+
if (compression == DEFAULT.getCompression())
59+
return DEFAULT;
60+
return builder().compression(compression).build();
61+
}
62+
63+
public static ZipEntrySettings of(Compression compression, Encryption encryption, char[] password) {
64+
if (encryption == Encryption.OFF)
65+
return of(compression);
66+
return builder()
67+
.compression(compression)
68+
.encryption(encryption, password).build();
69+
}
70+
71+
public static ZipEntrySettings of(Encryption encryption, char[] password) {
72+
if (encryption == Encryption.OFF)
73+
return of(DEFAULT.getCompression());
74+
return builder().encryption(encryption, password).build();
75+
}
76+
5777
public Builder toBuilder() {
5878
return new Builder(this);
5979
}
@@ -73,6 +93,7 @@ private ZipEntrySettings(Builder builder) {
7393
@SuppressWarnings("PMD.UnusedAssignment")
7494
public static final class Builder {
7595

96+
7697
private Compression compression = Compression.DEFLATE;
7798
private CompressionLevel compressionLevel = CompressionLevel.NORMAL;
7899
private Encryption encryption = Encryption.OFF;
@@ -100,6 +121,10 @@ public ZipEntrySettings build() {
100121
return new ZipEntrySettings(this);
101122
}
102123

124+
public ZipEntrySettings.Builder compression(Compression compression) {
125+
return compression(compression, CompressionLevel.NORMAL);
126+
}
127+
103128
public ZipEntrySettings.Builder compression(Compression compression, CompressionLevel compressionLevel) {
104129
this.compression = compression;
105130
this.compressionLevel = compressionLevel;

src/main/java/ru/olegcherednik/zip4jvm/utils/ValidationUtils.java

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public static void requireExists(Path path) {
6666
throw new PathNotExistsException(path);
6767
}
6868

69+
public static void requireExists(Collection<Path> paths) {
70+
paths.forEach(ValidationUtils::requireExists);
71+
}
72+
6973
public static void requireRegularFile(Path path, String name) {
7074
if (Files.exists(path) && !Files.isRegularFile(path))
7175
throw new IllegalArgumentException("Path should be a regular file: " + name);

src/test/java/ru/olegcherednik/zip4jvm/TestData.java

-9
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ public final class TestData {
5454
public static final String dirNameCars = "cars";
5555
public static final String dirNameEmpty = "empty_dir";
5656

57-
public static final String zipDirNameBikes = dirNameBikes + '/';
58-
public static final String zipDirNameCars = dirNameCars + '/';
59-
public static final String zipDirNameEmpty = dirNameEmpty + '/';
60-
6157
public static final String fileNameZipSrc = "src.zip";
6258
public static final String fileNameDataSrc = "src.data";
6359
public static final String fileNameDucati = "ducati-panigale-1199.jpg";
@@ -86,11 +82,6 @@ public final class TestData {
8682
public static final String symlinkAbsFileNameHonda = getAbsoluteSymlinkName(fileNameHonda);
8783
public static final String symlinkAbsDirNameData = getAbsoluteSymlinkName(dirNameSrcData);
8884

89-
public static final String zipSymlinkRelDirNameData = symlinkRelDirNameData + '/';
90-
public static final String zipSymlinkRelDirNameCars = symlinkRelDirNameCars + '/';
91-
public static final String zipSymlinkAbsDirNameData = symlinkAbsDirNameData + '/';
92-
public static final String zipSymlinkTrnDirNameData = symlinkTrnDirNameData + '/';
93-
9485
public static final Path dirBikes = dirSrcData.resolve(dirNameBikes);
9586
public static final Path dirCars = dirSrcData.resolve(dirNameCars);
9687
public static final Path dirEmpty = dirSrcData.resolve(dirNameEmpty);

src/test/java/ru/olegcherednik/zip4jvm/TestDataAssert.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
import java.nio.file.Path;
3333
import java.util.function.Consumer;
3434

35+
import static ru.olegcherednik.zip4jvm.TestData.dirNameBikes;
36+
import static ru.olegcherednik.zip4jvm.TestData.dirNameCars;
37+
import static ru.olegcherednik.zip4jvm.TestData.dirNameEmpty;
3538
import static ru.olegcherednik.zip4jvm.TestData.fileNameBentley;
3639
import static ru.olegcherednik.zip4jvm.TestData.fileNameDucati;
3740
import static ru.olegcherednik.zip4jvm.TestData.fileNameEmpty;
@@ -43,9 +46,6 @@
4346
import static ru.olegcherednik.zip4jvm.TestData.fileNameSigSauer;
4447
import static ru.olegcherednik.zip4jvm.TestData.fileNameSuzuki;
4548
import static ru.olegcherednik.zip4jvm.TestData.fileNameWiesmann;
46-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameBikes;
47-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameCars;
48-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameEmpty;
4949

5050
/**
5151
* @author Oleg Cherednik
@@ -102,9 +102,9 @@ public final class TestDataAssert {
102102
public static final Consumer<IDirectoryAssert<?>> rootAssert = dir -> {
103103
dir.exists().hasEntries(8).hasDirectories(3).hasRegularFiles(5);
104104

105-
dirBikesAssert.accept(dir.directory(zipDirNameBikes));
106-
dirCarsAssert.accept(dir.directory(zipDirNameCars));
107-
dirEmptyAssert.accept(dir.directory(zipDirNameEmpty));
105+
dirBikesAssert.accept(dir.directory(dirNameBikes));
106+
dirCarsAssert.accept(dir.directory(dirNameCars));
107+
dirEmptyAssert.accept(dir.directory(dirNameEmpty));
108108

109109
fileMcdonnelDouglasAssert.accept(dir.regularFile(fileNameMcdonnelDouglas));
110110
fileSaintPetersburgAssert.accept(dir.regularFile(fileNameSaintPetersburg));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package ru.olegcherednik.zip4jvm;
20+
21+
import ru.olegcherednik.zip4jvm.model.Encryption;
22+
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
23+
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettingsProvider;
24+
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
25+
26+
import org.testng.annotations.Test;
27+
28+
import java.io.IOException;
29+
import java.nio.file.Path;
30+
31+
import static ru.olegcherednik.zip4jvm.TestData.dirCars;
32+
import static ru.olegcherednik.zip4jvm.TestData.fileBentley;
33+
import static ru.olegcherednik.zip4jvm.TestData.fileNameBentley;
34+
import static ru.olegcherednik.zip4jvm.TestDataAssert.dirCarsAssert;
35+
import static ru.olegcherednik.zip4jvm.TestDataAssert.fileBentleyAssert;
36+
import static ru.olegcherednik.zip4jvm.assertj.Zip4jvmAssertions.assertThatDirectory;
37+
import static ru.olegcherednik.zip4jvm.assertj.Zip4jvmAssertions.assertThatZipFile;
38+
39+
/**
40+
* @author Oleg Cherednik
41+
* @since 20.10.2024
42+
*/
43+
@Test
44+
@SuppressWarnings("FieldNamingConvention")
45+
public class ZipSpecialTest {
46+
47+
private static final Path rootDir = Zip4jvmSuite.generateSubDirNameWithTime(ZipSpecialTest.class);
48+
49+
public void shouldAddRegularFileWhenSameNameAndDifferentDestPath() throws IOException {
50+
final char[] one = "1".toCharArray();
51+
final char[] two = "2".toCharArray();
52+
53+
final String oneEntryName = "one/" + fileNameBentley;
54+
final String twoEntryName = "two/" + fileNameBentley;
55+
final String threeEntryName = "three/" + fileNameBentley;
56+
57+
ZipSettings settings = ZipSettings.builder()
58+
.entrySettingsProvider(ZipEntrySettingsProvider.of(entryName -> {
59+
if (entryName.equals(oneEntryName))
60+
return ZipEntrySettings.of(Encryption.AES_256, one);
61+
if (entryName.equals(twoEntryName))
62+
return ZipEntrySettings.of(Encryption.AES_256, two);
63+
return null;
64+
})).build();
65+
66+
Path zip = Zip4jvmSuite.subDirNameAsMethodName(rootDir).resolve("src.zip");
67+
68+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
69+
zipFile.addWithMove(fileBentley, "one");
70+
zipFile.addWithMove(fileBentley, "two");
71+
zipFile.addWithMove(fileBentley, "three");
72+
}
73+
74+
assertThatDirectory(zip.getParent()).exists().hasOnlyRegularFiles(1);
75+
assertThatZipFile(zip).root().hasEntries(3).hasDirectories(3).hasRegularFiles(0);
76+
assertThatZipFile(zip, one).regularFile(oneEntryName).matches(fileBentleyAssert);
77+
assertThatZipFile(zip, two).regularFile(twoEntryName).matches(fileBentleyAssert);
78+
assertThatZipFile(zip).regularFile(threeEntryName).matches(fileBentleyAssert);
79+
}
80+
81+
public void shouldAddDirectoryWhenSameNameAndDifferentDestPath() throws IOException {
82+
final char[] one = "1".toCharArray();
83+
final char[] two = "2".toCharArray();
84+
85+
ZipSettings settings = ZipSettings.builder()
86+
.entrySettingsProvider(ZipEntrySettingsProvider.of(entryName -> {
87+
if (entryName.startsWith("one/"))
88+
return ZipEntrySettings.of(Encryption.AES_256, one);
89+
if (entryName.startsWith("two/"))
90+
return ZipEntrySettings.of(Encryption.AES_256, two);
91+
return null;
92+
}))
93+
.removeRootDir(true)
94+
.build();
95+
96+
Path zip = Zip4jvmSuite.subDirNameAsMethodName(rootDir).resolve("src.zip");
97+
98+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
99+
zipFile.addWithMove(dirCars, "one");
100+
zipFile.addWithMove(dirCars, "two");
101+
zipFile.addWithMove(dirCars, "three");
102+
}
103+
104+
assertThatDirectory(zip.getParent()).exists().hasOnlyRegularFiles(1);
105+
assertThatZipFile(zip).root().hasEntries(3).hasDirectories(3).hasRegularFiles(0);
106+
assertThatZipFile(zip, one).directory("one").matches(dirCarsAssert);
107+
assertThatZipFile(zip, two).directory("two").matches(dirCarsAssert);
108+
assertThatZipFile(zip).directory("three").matches(dirCarsAssert);
109+
}
110+
111+
}

src/test/java/ru/olegcherednik/zip4jvm/assertj/ZipEntryDirectoryAssert.java

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ public ZipEntryDirectoryAssert hasSymlinks(int expected) {
9797

9898
@Override
9999
public ZipEntryDirectoryAssert directory(String name) {
100+
if (!name.endsWith("/"))
101+
name += '/';
100102
return new ZipEntryDirectoryAssert(getEntry(name), zipFile);
101103
}
102104

src/test/java/ru/olegcherednik/zip4jvm/assertj/ZipFileAssert.java

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public ZipEntryDirectoryAssert root() {
4242
}
4343

4444
public ZipEntryDirectoryAssert directory(String name) {
45+
if (!name.endsWith("/"))
46+
name += '/';
47+
4548
ZipArchiveEntry entry = new ZipArchiveEntry(name);
4649

4750
if (!entry.isDirectory())

src/test/java/ru/olegcherednik/zip4jvm/assertj/ZipFileDecorator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
* @author Oleg Cherednik
3939
* @since 27.03.2019
4040
*/
41-
abstract class ZipFileDecorator {
41+
public abstract class ZipFileDecorator {
4242

4343
protected static final String SLASH = "/";
4444
protected static final char SLASH_CHAR = '/';

src/test/java/ru/olegcherednik/zip4jvm/assertj/ZipFileSolidNoEncryptedDecorator.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ else if (zipEntry.getMethod() == ZipMethod.LZMA.getCode()) {
9898
assertThat(total).isEqualTo(decompressed.length);
9999

100100
delegate = new ByteArrayInputStream(decompressed);
101-
} else
101+
} else if (zipEntry.getMethod() == ZipMethod.AES_ENCRYPTED.getCode())
102+
throw new UnsupportedOperationException(
103+
"ZipEntry password id not correct: " + zipEntry.getName());
104+
else
102105
throw new UnsupportedOperationException("ZipEntry data can't be read: " + zipEntry.getName());
103106
}
104107

src/test/java/ru/olegcherednik/zip4jvm/model/entry/ZipEntryTest.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import static ru.olegcherednik.zip4jvm.TestData.dirNameBikes;
3030
import static ru.olegcherednik.zip4jvm.TestData.fileBentley;
3131
import static ru.olegcherednik.zip4jvm.TestData.fileNameBentley;
32-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameBikes;
3332

3433
/**
3534
* @author Oleg Cherednik
@@ -43,6 +42,6 @@ public void shouldRetrieveFileNameWhenToString() throws IOException {
4342
ZipEntry dir = ZipEntryBuilder.emptyDirectory(dirBikes, dirNameBikes, ZipEntrySettings.DEFAULT);
4443

4544
assertThat(file.toString()).isEqualTo(fileNameBentley);
46-
assertThat(dir.toString()).isEqualTo(zipDirNameBikes);
45+
assertThat(dir.toString()).isEqualTo(dirNameBikes + '/');
4746
}
4847
}

0 commit comments

Comments
 (0)