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