1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.archivers.zip;
18
19 import java.nio.file.attribute.FileTime;
20 import java.util.Date;
21 import java.util.Objects;
22 import java.util.zip.ZipException;
23
24 import org.apache.commons.io.file.attribute.FileTimes;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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 public class X000A_NTFS implements ZipExtraField {
69
70
71
72
73
74
75 public static final ZipShort HEADER_ID = new ZipShort(0x000a);
76
77 private static final ZipShort TIME_ATTR_TAG = new ZipShort(0x0001);
78 private static final ZipShort TIME_ATTR_SIZE = new ZipShort(3 * 8);
79
80 private static ZipEightByteInteger dateToZip(final Date d) {
81 if (d == null) {
82 return null;
83 }
84 return new ZipEightByteInteger(FileTimes.toNtfsTime(d));
85 }
86
87 private static ZipEightByteInteger fileTimeToZip(final FileTime time) {
88 if (time == null) {
89 return null;
90 }
91 return new ZipEightByteInteger(FileTimes.toNtfsTime(time));
92 }
93
94 private static Date zipToDate(final ZipEightByteInteger z) {
95 if (z == null || ZipEightByteInteger.ZERO.equals(z)) {
96 return null;
97 }
98 return FileTimes.ntfsTimeToDate(z.getLongValue());
99 }
100
101 private static FileTime zipToFileTime(final ZipEightByteInteger z) {
102 if (z == null || ZipEightByteInteger.ZERO.equals(z)) {
103 return null;
104 }
105 return FileTimes.ntfsTimeToFileTime(z.getLongValue());
106 }
107
108 private ZipEightByteInteger modifyTime = ZipEightByteInteger.ZERO;
109
110 private ZipEightByteInteger accessTime = ZipEightByteInteger.ZERO;
111
112 private ZipEightByteInteger createTime = ZipEightByteInteger.ZERO;
113
114 @Override
115 public boolean equals(final Object o) {
116 if (o instanceof X000A_NTFS) {
117 final X000A_NTFS xf = (X000A_NTFS) o;
118
119 return Objects.equals(modifyTime, xf.modifyTime) && Objects.equals(accessTime, xf.accessTime) && Objects.equals(createTime, xf.createTime);
120 }
121 return false;
122 }
123
124
125
126
127
128
129
130 public FileTime getAccessFileTime() {
131 return zipToFileTime(accessTime);
132 }
133
134
135
136
137
138
139 public Date getAccessJavaTime() {
140 return zipToDate(accessTime);
141 }
142
143
144
145
146
147
148
149 public ZipEightByteInteger getAccessTime() {
150 return accessTime;
151 }
152
153
154
155
156
157
158 @Override
159 public byte[] getCentralDirectoryData() {
160 return getLocalFileDataData();
161 }
162
163
164
165
166
167
168
169
170
171
172 @Override
173 public ZipShort getCentralDirectoryLength() {
174 return getLocalFileDataLength();
175 }
176
177
178
179
180
181
182
183 public FileTime getCreateFileTime() {
184 return zipToFileTime(createTime);
185 }
186
187
188
189
190
191
192 public Date getCreateJavaTime() {
193 return zipToDate(createTime);
194 }
195
196
197
198
199
200
201
202 public ZipEightByteInteger getCreateTime() {
203 return createTime;
204 }
205
206
207
208
209
210
211 @Override
212 public ZipShort getHeaderId() {
213 return HEADER_ID;
214 }
215
216
217
218
219
220
221 @Override
222 public byte[] getLocalFileDataData() {
223 final byte[] data = new byte[getLocalFileDataLength().getValue()];
224 int pos = 4;
225 System.arraycopy(TIME_ATTR_TAG.getBytes(), 0, data, pos, 2);
226 pos += 2;
227 System.arraycopy(TIME_ATTR_SIZE.getBytes(), 0, data, pos, 2);
228 pos += 2;
229 System.arraycopy(modifyTime.getBytes(), 0, data, pos, 8);
230 pos += 8;
231 System.arraycopy(accessTime.getBytes(), 0, data, pos, 8);
232 pos += 8;
233 System.arraycopy(createTime.getBytes(), 0, data, pos, 8);
234 return data;
235 }
236
237
238
239
240
241
242 @Override
243 public ZipShort getLocalFileDataLength() {
244 return new ZipShort(4
245 + 2
246 + 2
247 + 3 * 8 );
248 }
249
250
251
252
253
254
255
256 public FileTime getModifyFileTime() {
257 return zipToFileTime(modifyTime);
258 }
259
260
261
262
263
264
265 public Date getModifyJavaTime() {
266 return zipToDate(modifyTime);
267 }
268
269
270
271
272
273
274
275 public ZipEightByteInteger getModifyTime() {
276 return modifyTime;
277 }
278
279 @Override
280 public int hashCode() {
281 int hc = -123;
282 if (modifyTime != null) {
283 hc ^= modifyTime.hashCode();
284 }
285 if (accessTime != null) {
286
287
288 hc ^= Integer.rotateLeft(accessTime.hashCode(), 11);
289 }
290 if (createTime != null) {
291 hc ^= Integer.rotateLeft(createTime.hashCode(), 22);
292 }
293 return hc;
294 }
295
296
297
298
299 @Override
300 public void parseFromCentralDirectoryData(final byte[] buffer, final int offset, final int length) throws ZipException {
301 reset();
302 parseFromLocalFileData(buffer, offset, length);
303 }
304
305
306
307
308
309
310
311
312
313 @Override
314 public void parseFromLocalFileData(final byte[] data, int offset, final int length) throws ZipException {
315 final int len = offset + length;
316
317
318 offset += 4;
319
320 while (offset + 4 <= len) {
321 final ZipShort tag = new ZipShort(data, offset);
322 offset += 2;
323 if (tag.equals(TIME_ATTR_TAG)) {
324 readTimeAttr(data, offset, len - offset);
325 break;
326 }
327 final ZipShort size = new ZipShort(data, offset);
328 offset += 2 + size.getValue();
329 }
330 }
331
332 private void readTimeAttr(final byte[] data, int offset, final int length) {
333 if (length >= 2 + 3 * 8) {
334 final ZipShort tagValueLength = new ZipShort(data, offset);
335 if (TIME_ATTR_SIZE.equals(tagValueLength)) {
336 offset += 2;
337 modifyTime = new ZipEightByteInteger(data, offset);
338 offset += 8;
339 accessTime = new ZipEightByteInteger(data, offset);
340 offset += 8;
341 createTime = new ZipEightByteInteger(data, offset);
342 }
343 }
344 }
345
346
347
348
349 private void reset() {
350 this.modifyTime = ZipEightByteInteger.ZERO;
351 this.accessTime = ZipEightByteInteger.ZERO;
352 this.createTime = ZipEightByteInteger.ZERO;
353 }
354
355
356
357
358
359
360
361 public void setAccessFileTime(final FileTime time) {
362 setAccessTime(fileTimeToZip(time));
363 }
364
365
366
367
368
369
370 public void setAccessJavaTime(final Date d) {
371 setAccessTime(dateToZip(d));
372 }
373
374
375
376
377
378
379 public void setAccessTime(final ZipEightByteInteger t) {
380 accessTime = t == null ? ZipEightByteInteger.ZERO : t;
381 }
382
383
384
385
386
387
388
389 public void setCreateFileTime(final FileTime time) {
390 setCreateTime(fileTimeToZip(time));
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404 public void setCreateJavaTime(final Date d) {
405 setCreateTime(dateToZip(d));
406 }
407
408
409
410
411
412
413 public void setCreateTime(final ZipEightByteInteger t) {
414 createTime = t == null ? ZipEightByteInteger.ZERO : t;
415 }
416
417
418
419
420
421
422
423 public void setModifyFileTime(final FileTime time) {
424 setModifyTime(fileTimeToZip(time));
425 }
426
427
428
429
430
431
432 public void setModifyJavaTime(final Date d) {
433 setModifyTime(dateToZip(d));
434 }
435
436
437
438
439
440
441 public void setModifyTime(final ZipEightByteInteger t) {
442 modifyTime = t == null ? ZipEightByteInteger.ZERO : t;
443 }
444
445
446
447
448
449
450 @Override
451 public String toString() {
452
453 return new StringBuilder()
454 .append("0x000A Zip Extra Field:")
455 .append(" Modify:[")
456 .append(getModifyFileTime())
457 .append("] ")
458 .append(" Access:[")
459 .append(getAccessFileTime())
460 .append("] ")
461 .append(" Create:[")
462 .append(getCreateFileTime())
463 .append("] ")
464 .toString();
465
466 }
467 }