1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.compress.archivers.zip;
21
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25 import static org.junit.jupiter.api.Assertions.assertEquals;
26 import static org.junit.jupiter.api.Assertions.assertSame;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28
29 import java.math.BigInteger;
30 import java.time.Instant;
31 import java.time.LocalDateTime;
32 import java.time.ZoneId;
33 import java.util.Calendar;
34 import java.util.Date;
35
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.Test;
38
39 class ZipUtilTest {
40
41 static void assertDosDate(final long value, final int year, final int month, final int day, final int hour, final int minute, final int second) {
42 int pos = 0;
43 assertEquals(year - 1980, (int) (value << pos) >>> 32 - 7);
44 assertEquals(month, (int) (value << (pos += 7)) >>> 32 - 4);
45 assertEquals(day, (int) (value << (pos += 4)) >>> 32 - 5);
46 assertEquals(hour, (int) (value << (pos += 5)) >>> 32 - 5);
47 assertEquals(minute, (int) (value << (pos += 5)) >>> 32 - 6);
48 assertEquals(second, (int) (value << pos + 6) >>> 32 - 5 << 1);
49 }
50
51 static Instant toLocalInstant(final String date) {
52 return LocalDateTime.parse(date).atZone(ZoneId.systemDefault()).toInstant();
53 }
54
55 private Date time;
56
57 private ZipLong zl;
58
59 @BeforeEach
60 public void setUp() throws Exception {
61 time = new Date();
62 final Calendar cal = Calendar.getInstance();
63 cal.setTime(time);
64 final int year = cal.get(Calendar.YEAR);
65 final int month = cal.get(Calendar.MONTH) + 1;
66
67 final long value = year - 1980 << 25
68 | month << 21
69 | cal.get(Calendar.DAY_OF_MONTH) << 16
70 | cal.get(Calendar.HOUR_OF_DAY) << 11
71 | cal.get(Calendar.MINUTE) << 5
72 | cal.get(Calendar.SECOND) >> 1;
73
74
75 final byte[] result = new byte[4];
76 result[0] = (byte) (value & 0xFF);
77 result[1] = (byte) ((value & 0xFF00) >> 8);
78 result[2] = (byte) ((value & 0xFF0000) >> 16);
79 result[3] = (byte) ((value & 0xFF000000L) >> 24);
80 zl = new ZipLong(result);
81 }
82
83 @Test
84 void testAdjustToLong() {
85 assertEquals(Integer.MAX_VALUE, ZipUtil.adjustToLong(Integer.MAX_VALUE));
86 assertEquals((long) Integer.MAX_VALUE + 1, ZipUtil.adjustToLong(Integer.MAX_VALUE + 1));
87 assertEquals(2 * (long) Integer.MAX_VALUE, ZipUtil.adjustToLong(2 * Integer.MAX_VALUE));
88 }
89
90 @Test
91 void testBigToLong() {
92 final BigInteger big1 = BigInteger.valueOf(1);
93 final BigInteger big2 = BigInteger.valueOf(Long.MAX_VALUE);
94 final BigInteger big3 = BigInteger.valueOf(Long.MIN_VALUE);
95
96 assertEquals(1L, ZipUtil.toLong(big1));
97 assertEquals(Long.MAX_VALUE, ZipUtil.toLong(big2));
98 assertEquals(Long.MIN_VALUE, ZipUtil.toLong(big3));
99
100 final BigInteger big4 = big2.add(big1);
101 assertThrows(IllegalArgumentException.class, () -> ZipUtil.toLong(big4), "Should have thrown IllegalArgumentException");
102
103 final BigInteger big5 = big3.subtract(big1);
104 assertThrows(IllegalArgumentException.class, () -> ZipUtil.toLong(big5),
105 "ZipUtil.bigToLong(BigInteger) should have thrown IllegalArgumentException");
106 }
107
108 @Test
109 void testFromDosTime() {
110 ZipLong testDosTime = new ZipLong(1 << 21);
111 final Calendar cal = Calendar.getInstance();
112 cal.set(Calendar.YEAR, 1980);
113 cal.set(Calendar.MONTH, 0);
114 cal.set(Calendar.DATE, 0);
115 cal.set(Calendar.HOUR_OF_DAY, 0);
116 cal.set(Calendar.MINUTE, 0);
117 cal.set(Calendar.SECOND, 0);
118 cal.set(Calendar.MILLISECOND, 0);
119 Date testDate = ZipUtil.fromDosTime(testDosTime);
120 assertEquals(testDate.getTime(), cal.getTime().getTime());
121
122 testDosTime = ZipUtil.toDosTime(time);
123 testDate = ZipUtil.fromDosTime(testDosTime);
124
125 assertEquals(testDate.getTime() / 2000, time.getTime() / 2000);
126 }
127
128 @Test
129 void testInsideCalendar() {
130 final long date = toLocalInstant("1985-02-01T09:00:00").toEpochMilli();
131 final byte[] b1 = ZipUtil.toDosTime(date);
132 assertEquals(0, b1[0]);
133 assertEquals(72, b1[1]);
134 assertEquals(65, b1[2]);
135 assertEquals(10, b1[3]);
136 }
137
138 @Test
139 void testInsideCalendar_bigValue() {
140 final long date = toLocalInstant("2097-11-27T23:59:59").toEpochMilli();
141 final long value = ZipLong.getValue(ZipUtil.toDosTime(date));
142 assertDosDate(value, 2097, 11, 27, 23, 59, 58);
143 }
144
145 @Test
146 void testInsideCalendar_long() {
147 final long date = toLocalInstant("1985-02-01T09:00:00").toEpochMilli();
148 final long value = ZipLong.getValue(ZipUtil.toDosTime(date));
149 assertDosDate(value, 1985, 2, 1, 9, 0, 0);
150 }
151
152 @Test
153 void testInsideCalendar_modernDate() {
154 final long date = toLocalInstant("2022-12-27T16:18:23").toEpochMilli();
155 final long value = ZipLong.getValue(ZipUtil.toDosTime(date));
156 assertDosDate(value, 2022, 12, 27, 16, 18, 22);
157 }
158
159 @Test
160 void testIsDosTime() {
161 assertFalse(ZipUtil.isDosTime(toLocalInstant("1975-01-31T23:00:00").toEpochMilli()));
162 assertTrue(ZipUtil.isDosTime(toLocalInstant("1980-01-03T00:00:00").toEpochMilli()));
163 assertTrue(ZipUtil.isDosTime(toLocalInstant("2097-11-27T00:00:00").toEpochMilli()));
164 assertFalse(ZipUtil.isDosTime(toLocalInstant("2099-01-01T00:00:00").toEpochMilli()));
165
166 final long lowestExpressableDosTime = 1 << 21 | 1 << 16;
167 assertTrue(ZipUtil.isDosTime(ZipUtil.dosToJavaTime(lowestExpressableDosTime)));
168 }
169
170 @Test
171 void testLongToBig() {
172 final long l0 = 0;
173 final long l1 = 1;
174 final long l2 = -1;
175 final long l3 = Integer.MIN_VALUE;
176 final long l4 = Long.MAX_VALUE;
177 final long l5 = Long.MIN_VALUE;
178
179 final BigInteger big0 = ZipUtil.longToBig(l0);
180 final BigInteger big1 = ZipUtil.longToBig(l1);
181 final BigInteger big2 = ZipUtil.longToBig(l2);
182 final BigInteger big3 = ZipUtil.longToBig(l3);
183 final BigInteger big4 = ZipUtil.longToBig(l4);
184
185 assertEquals(0, big0.longValue());
186 assertEquals(1, big1.longValue());
187 assertEquals(0xFFFFFFFFL, big2.longValue());
188 assertEquals(0x80000000L, big3.longValue());
189 assertEquals(Long.MAX_VALUE, big4.longValue());
190
191 assertThrows(IllegalArgumentException.class, () -> ZipUtil.longToBig(l5), "ZipUtil.longToBig(long) should have thrown IllegalArgumentException");
192 }
193
194 @Test
195 void testMinTime() {
196 final byte[] b1 = ZipUtil.toDosTime(0);
197 final byte b10 = b1[0];
198 b1[0]++;
199 final byte[] b2 = ZipUtil.toDosTime(0);
200 assertEquals(b10, b2[0]);
201 }
202
203 @Test
204 void testOutsideCalendar() {
205 final long date = toLocalInstant("1975-01-31T23:00:00").toEpochMilli();
206 final byte[] b1 = ZipUtil.toDosTime(date);
207 assertEquals(0, b1[0]);
208 assertEquals(0, b1[1]);
209 assertEquals(33, b1[2]);
210 assertEquals(0, b1[3]);
211 }
212
213 @Test
214 void testOutsideCalendar_long() {
215 final long date = toLocalInstant("1975-01-31T23:00:00").toEpochMilli();
216 final long value = ZipLong.getValue(ZipUtil.toDosTime(date));
217 assertDosDate(value, 1980, 1, 1, 0, 0, 0);
218 }
219
220 @Test
221 void testReverse() {
222 final byte[][] bTest = new byte[6][];
223 bTest[0] = new byte[] {};
224 bTest[1] = new byte[] { 1 };
225 bTest[2] = new byte[] { 1, 2 };
226 bTest[3] = new byte[] { 1, 2, 3 };
227 bTest[4] = new byte[] { 1, 2, 3, 4 };
228 bTest[5] = new byte[] { 1, 2, 3, 4, 5 };
229
230 final byte[][] rTest = new byte[6][];
231 rTest[0] = new byte[] {};
232 rTest[1] = new byte[] { 1 };
233 rTest[2] = new byte[] { 2, 1 };
234 rTest[3] = new byte[] { 3, 2, 1 };
235 rTest[4] = new byte[] { 4, 3, 2, 1 };
236 rTest[5] = new byte[] { 5, 4, 3, 2, 1 };
237
238 assertEquals(bTest.length, rTest.length, "test and result arrays are same length");
239
240 for (int i = 0; i < bTest.length; i++) {
241 final byte[] result = ZipUtil.reverse(bTest[i]);
242 assertSame(bTest[i], result, "reverse mutates in-place");
243 assertArrayEquals(rTest[i], result, "reverse actually reverses");
244 }
245 }
246
247 @Test
248 void testSignedByteToUnsignedInt() {
249
250 int expectedVal = 128;
251 for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
252 final byte b = (byte) i;
253 assertEquals(expectedVal, Byte.toUnsignedInt(b));
254 expectedVal++;
255 if (expectedVal == 256) {
256 expectedVal = 0;
257 }
258 }
259 }
260
261 @Test
262 void testUnknownMethod() throws Exception {
263 final ZipArchiveEntry ze = new ZipArchiveEntry();
264 ze.setMethod(100);
265 assertThrows(UnsupportedZipFeatureException.class, () -> ZipUtil.checkRequestedFeatures(ze));
266 }
267
268 @Test
269 void testUnsignedIntToSignedByte() {
270 int unsignedVal = 128;
271 for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
272 final byte expectedVal = (byte) i;
273 assertEquals(expectedVal, ZipUtil.unsignedIntToSignedByte(unsignedVal));
274 unsignedVal++;
275 if (unsignedVal == 256) {
276 unsignedVal = 0;
277 }
278 }
279
280 assertThrows(IllegalArgumentException.class, () -> ZipUtil.unsignedIntToSignedByte(-1),
281 "ZipUtil.unsignedIntToSignedByte(-1) should have thrown IllegalArgumentException");
282
283 assertThrows(IllegalArgumentException.class, () -> ZipUtil.unsignedIntToSignedByte(256),
284 "ZipUtil.unsignedIntToSignedByte(256) should have thrown IllegalArgumentException");
285 }
286
287 @Test
288 void testUnsupportedMethod() throws Exception {
289 final ZipArchiveEntry ze = new ZipArchiveEntry();
290 ze.setMethod(ZipMethod.EXPANDING_LEVEL_1.getCode());
291 assertThrows(UnsupportedZipFeatureException.class, () -> ZipUtil.checkRequestedFeatures(ze));
292 }
293
294 @Test
295 void testZipLong() {
296 final ZipLong test = ZipUtil.toDosTime(time);
297 assertEquals(test.getValue(), zl.getValue());
298 }
299 }