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