1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.archivers.zip;
20
21 import java.io.IOException;
22 import java.math.BigInteger;
23 import java.time.Instant;
24 import java.time.LocalDateTime;
25 import java.time.ZoneId;
26 import java.util.Arrays;
27 import java.util.Calendar;
28 import java.util.Date;
29 import java.util.zip.CRC32;
30 import java.util.zip.ZipEntry;
31 import java.util.zip.ZipException;
32
33
34
35
36
37
38 public abstract class ZipUtil {
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 private static final long DOSTIME_BEFORE_1980 = 1 << 21 | 1 << 16;
81
82
83 private static final long DOSTIME_BEFORE_1980_AS_JAVA_TIME = dosToJavaTime(DOSTIME_BEFORE_1980);
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 private static final long UPPER_DOSTIME_BOUND = 128L * 365 * 24 * 60 * 60 * 1000;
104
105
106
107
108
109
110
111 public static long adjustToLong(final int i) {
112 if (i < 0) {
113 return 2 * (long) Integer.MAX_VALUE + 2 + i;
114 }
115 return i;
116 }
117
118
119
120
121 static boolean canHandleEntryData(final ZipArchiveEntry entry) {
122 return supportsEncryptionOf(entry) && supportsMethodOf(entry);
123 }
124
125
126
127
128 static void checkRequestedFeatures(final ZipArchiveEntry ze) throws UnsupportedZipFeatureException {
129 if (!supportsEncryptionOf(ze)) {
130 throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.ENCRYPTION, ze);
131 }
132 if (!supportsMethodOf(ze)) {
133 final ZipMethod m = ZipMethod.getMethodByCode(ze.getMethod());
134 if (m == null) {
135 throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.METHOD, ze);
136 }
137 throw new UnsupportedZipFeatureException(m, ze);
138 }
139 }
140
141
142
143
144 static byte[] copy(final byte[] from) {
145 if (from != null) {
146 return Arrays.copyOf(from, from.length);
147 }
148 return null;
149 }
150
151 static void copy(final byte[] from, final byte[] to, final int offset) {
152 if (from != null) {
153 System.arraycopy(from, 0, to, offset, from.length);
154 }
155 }
156
157 private static Date dosToJavaDate(final long dosTime) {
158 final Calendar cal = Calendar.getInstance();
159
160 cal.set(Calendar.YEAR, (int) (dosTime >> 25 & 0x7f) + 1980);
161 cal.set(Calendar.MONTH, (int) (dosTime >> 21 & 0x0f) - 1);
162 cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f);
163 cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f);
164 cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f);
165 cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e);
166 cal.set(Calendar.MILLISECOND, 0);
167
168 return cal.getTime();
169 }
170
171
172
173
174
175
176
177 public static long dosToJavaTime(final long dosTime) {
178 return dosToJavaDate(dosTime).getTime();
179 }
180
181
182
183
184
185
186
187 public static Date fromDosTime(final ZipLong zipDosTime) {
188 final long dosTime = zipDosTime.getValue();
189 return dosToJavaDate(dosTime);
190 }
191
192
193
194
195
196
197
198
199 private static String getUnicodeStringIfOriginalMatches(final AbstractUnicodeExtraField field, final byte[] originalNameBytes) {
200 if (field != null) {
201 final CRC32 crc32 = new CRC32();
202 crc32.update(originalNameBytes);
203 final long origCRC32 = crc32.getValue();
204
205 if (origCRC32 == field.getNameCRC32()) {
206 try {
207 return ZipEncodingHelper.ZIP_ENCODING_UTF_8.decode(field.getUnicodeName());
208 } catch (final IOException ignored) {
209
210
211 }
212 }
213 }
214
215 return null;
216 }
217
218
219
220
221
222
223
224
225 public static boolean isDosTime(final long time) {
226 return time <= UPPER_DOSTIME_BOUND &&
227 (time == DOSTIME_BEFORE_1980_AS_JAVA_TIME || javaToDosTime(time) != DOSTIME_BEFORE_1980);
228 }
229
230 private static LocalDateTime javaEpochToLocalDateTime(final long time) {
231 final Instant instant = Instant.ofEpochMilli(time);
232 return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
233 }
234
235
236 private static long javaToDosTime(final long t) {
237 final LocalDateTime ldt = javaEpochToLocalDateTime(t);
238 if (ldt.getYear() < 1980) {
239 return DOSTIME_BEFORE_1980;
240 }
241 return (ldt.getYear() - 1980 << 25 | ldt.getMonthValue() << 21 | ldt.getDayOfMonth() << 16 | ldt.getHour() << 11 | ldt.getMinute() << 5
242 | ldt.getSecond() >> 1) & 0xffffffffL;
243 }
244
245
246
247
248
249
250
251
252
253
254 static BigInteger longToBig(long l) {
255 if (l < Integer.MIN_VALUE) {
256 throw new IllegalArgumentException("Negative longs < -2^31 not permitted: [" + l + "]");
257 }
258 if (l < 0 && l >= Integer.MIN_VALUE) {
259
260
261 l = adjustToLong((int) l);
262 }
263 return BigInteger.valueOf(l);
264 }
265
266
267
268
269
270
271
272
273 static ZipException newZipException(final String message, final Throwable cause) {
274 return (ZipException) new ZipException(message).initCause(cause);
275 }
276
277
278
279
280
281
282
283
284 public static byte[] reverse(final byte[] array) {
285 final int z = array.length - 1;
286 for (int i = 0; i < array.length / 2; i++) {
287 final byte x = array[i];
288 array[i] = array[z - i];
289 array[z - i] = x;
290 }
291 return array;
292 }
293
294
295
296
297
298 static void setNameAndCommentFromExtraFields(final ZipArchiveEntry ze, final byte[] originalNameBytes, final byte[] commentBytes) {
299 final ZipExtraField nameCandidate = ze.getExtraField(UnicodePathExtraField.UPATH_ID);
300 final UnicodePathExtraField name = nameCandidate instanceof UnicodePathExtraField ? (UnicodePathExtraField) nameCandidate : null;
301 final String newName = getUnicodeStringIfOriginalMatches(name, originalNameBytes);
302 if (newName != null) {
303 ze.setName(newName);
304 ze.setNameSource(ZipArchiveEntry.NameSource.UNICODE_EXTRA_FIELD);
305 }
306
307 if (commentBytes != null && commentBytes.length > 0) {
308 final ZipExtraField cmtCandidate = ze.getExtraField(UnicodeCommentExtraField.UCOM_ID);
309 final UnicodeCommentExtraField cmt = cmtCandidate instanceof UnicodeCommentExtraField ? (UnicodeCommentExtraField) cmtCandidate : null;
310 final String newComment = getUnicodeStringIfOriginalMatches(cmt, commentBytes);
311 if (newComment != null) {
312 ze.setComment(newComment);
313 ze.setCommentSource(ZipArchiveEntry.CommentSource.UNICODE_EXTRA_FIELD);
314 }
315 }
316 }
317
318
319
320
321
322
323
324
325
326 @Deprecated
327 public static int signedByteToUnsignedInt(final byte b) {
328 return Byte.toUnsignedInt(b);
329 }
330
331
332
333
334
335
336 private static boolean supportsEncryptionOf(final ZipArchiveEntry entry) {
337 return !entry.getGeneralPurposeBit().usesEncryption();
338 }
339
340
341
342
343
344
345 private static boolean supportsMethodOf(final ZipArchiveEntry entry) {
346 final int method = entry.getMethod();
347 return method == ZipEntry.STORED || method == ZipMethod.UNSHRINKING.getCode()
348 || method == ZipMethod.IMPLODING.getCode() || method == ZipEntry.DEFLATED
349 || method == ZipMethod.ENHANCED_DEFLATED.getCode() || method == ZipMethod.BZIP2.getCode()
350 || ZipMethod.isZstd(method)
351 || method == ZipMethod.XZ.getCode();
352 }
353
354
355
356
357
358
359
360 public static ZipLong toDosTime(final Date time) {
361 return new ZipLong(toDosTime(time.getTime()));
362 }
363
364
365
366
367
368
369
370
371
372
373
374 public static byte[] toDosTime(final long t) {
375 final byte[] result = new byte[4];
376 toDosTime(t, result, 0);
377 return result;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 public static void toDosTime(final long t, final byte[] buf, final int offset) {
392 ZipLong.putLong(javaToDosTime(t), buf, offset);
393 }
394
395
396
397
398
399
400
401 static long toLong(final BigInteger big) {
402 try {
403 return big.longValueExact();
404 } catch (final ArithmeticException e) {
405 throw new NumberFormatException("The BigInteger cannot fit inside a 64 bit java long: [" + big + "]");
406 }
407 }
408
409
410
411
412
413
414
415
416
417 public static byte unsignedIntToSignedByte(final int i) {
418 if (i > 255 || i < 0) {
419 throw new IllegalArgumentException("Can only convert non-negative integers between [0,255] to byte: [" + i + "]");
420 }
421 if (i < 128) {
422 return (byte) i;
423 }
424 return (byte) (i - 256);
425 }
426 }