001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.commons.compress.archivers.sevenz;
018
019import java.nio.file.attribute.FileTime;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.Date;
023import java.util.Iterator;
024import java.util.LinkedList;
025import java.util.Objects;
026
027import org.apache.commons.compress.archivers.ArchiveEntry;
028import org.apache.commons.compress.utils.TimeUtils;
029
030/**
031 * An entry in a 7z archive.
032 *
033 * @NotThreadSafe
034 * @since 1.6
035 */
036public class SevenZArchiveEntry implements ArchiveEntry {
037
038    static final SevenZArchiveEntry[] EMPTY_SEVEN_Z_ARCHIVE_ENTRY_ARRAY = {};
039
040    /**
041     * Converts Java time to NTFS time.
042     * @param date the Java time
043     * @return the NTFS time
044     * @deprecated Use {@link TimeUtils#toNtfsTime(Date)} instead.
045     * @see TimeUtils#toNtfsTime(Date)
046     */
047    @Deprecated
048    public static long javaTimeToNtfsTime(final Date date) {
049        return TimeUtils.toNtfsTime(date);
050    }
051
052    /**
053     * Converts NTFS time (100 nanosecond units since 1 January 1601)
054     * to Java time.
055     * @param ntfsTime the NTFS time in 100 nanosecond units
056     * @return the Java time
057     * @deprecated Use {@link TimeUtils#ntfsTimeToDate(long)} instead.
058     * @see TimeUtils#ntfsTimeToDate(long)
059     */
060    @Deprecated
061    public static Date ntfsTimeToJavaTime(final long ntfsTime) {
062        return TimeUtils.ntfsTimeToDate(ntfsTime);
063    }
064
065    private String name;
066    private boolean hasStream;
067    private boolean isDirectory;
068    private boolean isAntiItem;
069    private boolean hasCreationDate;
070    private boolean hasLastModifiedDate;
071    private boolean hasAccessDate;
072    private FileTime creationDate;
073    private FileTime lastModifiedDate;
074    private FileTime accessDate;
075    private boolean hasWindowsAttributes;
076    private int windowsAttributes;
077    private boolean hasCrc;
078    private long crc, compressedCrc;
079
080    private long size, compressedSize;
081
082    private Iterable<? extends SevenZMethodConfiguration> contentMethods;
083
084    /**
085     * Constructs a new instance.
086     */
087    public SevenZArchiveEntry() {
088    }
089
090    @Override
091    public boolean equals(final Object obj) {
092        if (this == obj) {
093            return true;
094        }
095        if (obj == null || getClass() != obj.getClass()) {
096            return false;
097        }
098        final SevenZArchiveEntry other = (SevenZArchiveEntry) obj;
099        return
100            Objects.equals(name, other.name) &&
101            hasStream == other.hasStream &&
102            isDirectory == other.isDirectory &&
103            isAntiItem == other.isAntiItem &&
104            hasCreationDate == other.hasCreationDate &&
105            hasLastModifiedDate == other.hasLastModifiedDate &&
106            hasAccessDate == other.hasAccessDate &&
107            Objects.equals(creationDate, other.creationDate) &&
108            Objects.equals(lastModifiedDate, other.lastModifiedDate) &&
109            Objects.equals(accessDate, other.accessDate) &&
110            hasWindowsAttributes == other.hasWindowsAttributes &&
111            windowsAttributes == other.windowsAttributes &&
112            hasCrc == other.hasCrc &&
113            crc == other.crc &&
114            compressedCrc == other.compressedCrc &&
115            size == other.size &&
116            compressedSize == other.compressedSize &&
117            equalSevenZMethods(contentMethods, other.contentMethods);
118    }
119
120    private boolean equalSevenZMethods(final Iterable<? extends SevenZMethodConfiguration> c1,
121        final Iterable<? extends SevenZMethodConfiguration> c2) {
122        if (c1 == null) {
123            return c2 == null;
124        }
125        if (c2 == null) {
126            return false;
127        }
128        final Iterator<? extends SevenZMethodConfiguration> i2 = c2.iterator();
129        for (final SevenZMethodConfiguration element : c1) {
130            if (!i2.hasNext()) {
131                return false;
132            }
133            if (!element.equals(i2.next())) {
134                return false;
135            }
136        }
137        return !i2.hasNext();
138    }
139
140    /**
141     * Gets the access date.
142     * This is equivalent to {@link SevenZArchiveEntry#getAccessTime()}, but precision is truncated to milliseconds.
143     *
144     * @throws UnsupportedOperationException if the entry hasn't got an access date.
145     * @return the access date
146     * @see SevenZArchiveEntry#getAccessTime()
147     */
148    public Date getAccessDate() {
149        return TimeUtils.toDate(getAccessTime());
150    }
151
152    /**
153     * Gets the access time.
154     *
155     * @throws UnsupportedOperationException if the entry hasn't got an access time.
156     * @return the access time
157     * @since 1.23
158     */
159    public FileTime getAccessTime() {
160        if (hasAccessDate) {
161            return accessDate;
162        }
163        throw new UnsupportedOperationException(
164                "The entry doesn't have this timestamp");
165    }
166
167    /**
168     * Gets the compressed CRC.
169     *
170     * @return the compressed CRC
171     * @deprecated Use {@link #getCompressedCrcValue()} instead.
172     */
173    @Deprecated
174    int getCompressedCrc() {
175        return (int) compressedCrc;
176    }
177
178    /**
179     * Gets the compressed CRC.
180     *
181     * @since 1.7
182     * @return the CRC
183     */
184    long getCompressedCrcValue() {
185        return compressedCrc;
186    }
187
188    /**
189     * Gets this entry's compressed file size.
190     *
191     * @return This entry's compressed file size.
192     */
193    long getCompressedSize() {
194        return compressedSize;
195    }
196
197    /**
198     * Gets the (compression) methods to use for entry's content - the
199     * default is LZMA2.
200     *
201     * <p>Currently only {@link SevenZMethod#COPY}, {@link
202     * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link
203     * SevenZMethod#DEFLATE} are supported when writing archives.</p>
204     *
205     * <p>The methods will be consulted in iteration order to create
206     * the final output.</p>
207     *
208     * @since 1.8
209     * @return the methods to use for the content
210     */
211    public Iterable<? extends SevenZMethodConfiguration> getContentMethods() {
212        return contentMethods;
213    }
214
215    /**
216     * Gets the CRC.
217     * @deprecated use getCrcValue instead.
218     * @return the CRC
219     */
220    @Deprecated
221    public int getCrc() {
222        return (int) crc;
223    }
224
225    /**
226     * Gets the CRC.
227     *
228     * @since 1.7
229     * @return the CRC
230     */
231    public long getCrcValue() {
232        return crc;
233    }
234
235    /**
236     * Gets the creation date.
237     * This is equivalent to {@link SevenZArchiveEntry#getCreationTime()}, but precision is truncated to milliseconds.
238     *
239     * @throws UnsupportedOperationException if the entry hasn't got a creation date.
240     * @return the new creation date
241     * @see SevenZArchiveEntry#getCreationTime()
242     */
243    public Date getCreationDate() {
244        return TimeUtils.toDate(getCreationTime());
245    }
246
247    /**
248     * Gets the creation time.
249     *
250     * @throws UnsupportedOperationException if the entry hasn't got a creation time.
251     * @return the creation time
252     * @since 1.23
253     */
254    public FileTime getCreationTime() {
255        if (hasCreationDate) {
256            return creationDate;
257        }
258        throw new UnsupportedOperationException(
259                "The entry doesn't have this timestamp");
260    }
261
262    /**
263     * Gets whether this entry has got an access date at all.
264     * @return whether this entry has got an access date at all.
265     */
266    public boolean getHasAccessDate() {
267        return hasAccessDate;
268    }
269
270    /**
271     * Gets whether this entry has got a crc.
272     *
273     * <p>In general entries without streams don't have a CRC either.</p>
274     * @return whether this entry has got a crc.
275     */
276    public boolean getHasCrc() {
277        return hasCrc;
278    }
279
280    /**
281     * Gets whether this entry has got a creation date at all.
282     * @return whether the entry has got a creation date
283     */
284    public boolean getHasCreationDate() {
285        return hasCreationDate;
286    }
287
288    /**
289     * Gets whether this entry has got a last modified date at all.
290     * @return whether this entry has got a last modified date at all
291     */
292    public boolean getHasLastModifiedDate() {
293        return hasLastModifiedDate;
294    }
295
296    /**
297     * Gets whether this entry has windows attributes.
298     * @return whether this entry has windows attributes.
299     */
300    public boolean getHasWindowsAttributes() {
301        return hasWindowsAttributes;
302    }
303
304    /**
305     * Gets the last modified date.
306     * This is equivalent to {@link SevenZArchiveEntry#getLastModifiedTime()}, but precision is truncated to milliseconds.
307     *
308     * @throws UnsupportedOperationException if the entry hasn't got a last modified date.
309     * @return the last modified date
310     * @see SevenZArchiveEntry#getLastModifiedTime()
311     */
312    @Override
313    public Date getLastModifiedDate() {
314        return TimeUtils.toDate(getLastModifiedTime());
315    }
316
317    /**
318     * Gets the last modified time.
319     *
320     * @throws UnsupportedOperationException if the entry hasn't got a last modified time.
321     * @return the last modified time
322     * @since 1.23
323     */
324    public FileTime getLastModifiedTime() {
325        if (hasLastModifiedDate) {
326            return lastModifiedDate;
327        }
328        throw new UnsupportedOperationException(
329                "The entry doesn't have this timestamp");
330    }
331
332    /**
333     * Gets this entry's name.
334     *
335     * <p>This method returns the raw name as it is stored inside of the archive.</p>
336     *
337     * @return This entry's name.
338     */
339    @Override
340    public String getName() {
341        return name;
342    }
343
344    /**
345     * Gets this entry's file size.
346     *
347     * @return This entry's file size.
348     */
349    @Override
350    public long getSize() {
351        return size;
352    }
353
354    /**
355     * Gets the windows attributes.
356     * @return the windows attributes
357     */
358    public int getWindowsAttributes() {
359        return windowsAttributes;
360    }
361
362    @Override
363    public int hashCode() {
364        final String n = getName();
365        return n == null ? 0 : n.hashCode();
366    }
367
368    /**
369     * Tests whether there is any content associated with this entry.
370     *
371     * @return whether there is any content associated with this entry.
372     */
373    public boolean hasStream() {
374        return hasStream;
375    }
376
377    /**
378     * Tests whether this is an "anti-item" used in differential backups,
379     * meaning it should delete the same file from a previous backup.
380     *
381     * @return true if it is an anti-item, false otherwise
382     */
383    public boolean isAntiItem() {
384        return isAntiItem;
385    }
386
387    /**
388     * Tests whether or not this entry represents a directory.
389     *
390     * @return True if this entry is a directory.
391     */
392    @Override
393    public boolean isDirectory() {
394        return isDirectory;
395    }
396
397    /**
398     * Sets the access date.
399     *
400     * @param accessDate the new access date
401     * @see SevenZArchiveEntry#setAccessTime(FileTime)
402     */
403    public void setAccessDate(final Date accessDate) {
404        setAccessTime(TimeUtils.toFileTime(accessDate));
405    }
406
407    /**
408     * Sets the access date using NTFS time (100 nanosecond units
409     * since 1 January 1601)
410     * @param ntfsAccessDate the access date
411     */
412    public void setAccessDate(final long ntfsAccessDate) {
413        this.accessDate = TimeUtils.ntfsTimeToFileTime(ntfsAccessDate);
414    }
415
416    /**
417     * Sets the access time.
418     *
419     * @param time the new access time
420     * @since 1.23
421     */
422    public void setAccessTime(final FileTime time) {
423        hasAccessDate = time != null;
424        if (hasAccessDate) {
425            this.accessDate = time;
426        }
427    }
428
429    /**
430     * Sets whether this is an "anti-item" used in differential backups,
431     * meaning it should delete the same file from a previous backup.
432     * @param isAntiItem true if it is an anti-item, false otherwise
433     */
434    public void setAntiItem(final boolean isAntiItem) {
435        this.isAntiItem = isAntiItem;
436    }
437
438    /**
439     * Sets the compressed CRC.
440     * @deprecated use setCompressedCrcValue instead.
441     * @param crc the CRC
442     */
443    @Deprecated
444    void setCompressedCrc(final int crc) {
445        this.compressedCrc = crc;
446    }
447
448    /**
449     * Sets the compressed CRC.
450     * @since 1.7
451     * @param crc the CRC
452     */
453    void setCompressedCrcValue(final long crc) {
454        this.compressedCrc = crc;
455    }
456
457    /**
458     * Sets this entry's compressed file size.
459     *
460     * @param size This entry's new compressed file size.
461     */
462    void setCompressedSize(final long size) {
463        this.compressedSize = size;
464    }
465
466    /**
467     * Sets the (compression) methods to use for entry's content - the
468     * default is LZMA2.
469     *
470     * <p>Currently only {@link SevenZMethod#COPY}, {@link
471     * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link
472     * SevenZMethod#DEFLATE} are supported when writing archives.</p>
473     *
474     * <p>The methods will be consulted in iteration order to create
475     * the final output.</p>
476     *
477     * @param methods the methods to use for the content
478     * @since 1.8
479     */
480    public void setContentMethods(final Iterable<? extends SevenZMethodConfiguration> methods) {
481        if (methods != null) {
482            final LinkedList<SevenZMethodConfiguration> l = new LinkedList<>();
483            methods.forEach(l::addLast);
484            contentMethods = Collections.unmodifiableList(l);
485        } else {
486            contentMethods = null;
487        }
488    }
489
490    /**
491     * Sets the (compression) methods to use for entry's content - the
492     * default is LZMA2.
493     *
494     * <p>Currently only {@link SevenZMethod#COPY}, {@link
495     * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link
496     * SevenZMethod#DEFLATE} are supported when writing archives.</p>
497     *
498     * <p>The methods will be consulted in iteration order to create
499     * the final output.</p>
500     *
501     * @param methods the methods to use for the content
502     * @since 1.22
503     */
504    public void setContentMethods(final SevenZMethodConfiguration... methods) {
505        setContentMethods(Arrays.asList(methods));
506    }
507
508    /**
509     * Sets the CRC.
510     * @deprecated use setCrcValue instead.
511     * @param crc the CRC
512     */
513    @Deprecated
514    public void setCrc(final int crc) {
515        this.crc = crc;
516    }
517
518    /**
519     * Sets the CRC.
520     * @since 1.7
521     * @param crc the CRC
522     */
523    public void setCrcValue(final long crc) {
524        this.crc = crc;
525    }
526
527    /**
528     * Sets the creation date.
529     *
530     * @param creationDate the new creation date
531     * @see SevenZArchiveEntry#setCreationTime(FileTime)
532     */
533    public void setCreationDate(final Date creationDate) {
534        setCreationTime(TimeUtils.toFileTime(creationDate));
535    }
536
537    /**
538     * Sets the creation date using NTFS time (100 nanosecond units
539     * since 1 January 1601)
540     * @param ntfsCreationDate the creation date
541     */
542    public void setCreationDate(final long ntfsCreationDate) {
543        this.creationDate = TimeUtils.ntfsTimeToFileTime(ntfsCreationDate);
544    }
545
546    /**
547     * Sets the creation time.
548     *
549     * @param time the new creation time
550     * @since 1.23
551     */
552    public void setCreationTime(final FileTime time) {
553        hasCreationDate = time != null;
554        if (hasCreationDate) {
555            this.creationDate = time;
556        }
557    }
558
559    /**
560     * Sets whether or not this entry represents a directory.
561     *
562     * @param isDirectory True if this entry is a directory.
563     */
564    public void setDirectory(final boolean isDirectory) {
565        this.isDirectory = isDirectory;
566    }
567
568    /**
569     * Sets whether this entry has got an access date at all.
570     * @param hasAcessDate whether this entry has got an access date at all.
571     */
572    public void setHasAccessDate(final boolean hasAcessDate) {
573        this.hasAccessDate = hasAcessDate;
574    }
575
576    /**
577     * Sets whether this entry has got a crc.
578     * @param hasCrc whether this entry has got a crc.
579     */
580    public void setHasCrc(final boolean hasCrc) {
581        this.hasCrc = hasCrc;
582    }
583
584    /**
585     * Sets whether this entry has got a creation date at all.
586     * @param hasCreationDate whether the entry has got a creation date
587     */
588    public void setHasCreationDate(final boolean hasCreationDate) {
589        this.hasCreationDate = hasCreationDate;
590    }
591
592    /**
593     * Sets whether this entry has got a last modified date at all.
594     * @param hasLastModifiedDate whether this entry has got a last
595     * modified date at all
596     */
597    public void setHasLastModifiedDate(final boolean hasLastModifiedDate) {
598        this.hasLastModifiedDate = hasLastModifiedDate;
599    }
600
601    /**
602     * Sets whether there is any content associated with this entry.
603     * @param hasStream whether there is any content associated with this entry.
604     */
605    public void setHasStream(final boolean hasStream) {
606        this.hasStream = hasStream;
607    }
608
609    /**
610     * Sets whether this entry has windows attributes.
611     * @param hasWindowsAttributes whether this entry has windows attributes.
612     */
613    public void setHasWindowsAttributes(final boolean hasWindowsAttributes) {
614        this.hasWindowsAttributes = hasWindowsAttributes;
615    }
616
617    /**
618     * Sets the last modified date.
619     *
620     * @param lastModifiedDate the new last modified date
621     * @see SevenZArchiveEntry#setLastModifiedTime(FileTime)
622     */
623    public void setLastModifiedDate(final Date lastModifiedDate) {
624        setLastModifiedTime(TimeUtils.toFileTime(lastModifiedDate));
625    }
626
627    /**
628     * Sets the last modified date using NTFS time (100 nanosecond
629     * units since 1 January 1601)
630     * @param ntfsLastModifiedDate the last modified date
631     */
632    public void setLastModifiedDate(final long ntfsLastModifiedDate) {
633        this.lastModifiedDate = TimeUtils.ntfsTimeToFileTime(ntfsLastModifiedDate);
634    }
635
636    /**
637     * Sets the last modified time.
638     *
639     * @param time the new last modified time
640     * @since 1.23
641     */
642    public void setLastModifiedTime(final FileTime time) {
643        hasLastModifiedDate = time != null;
644        if (hasLastModifiedDate) {
645            this.lastModifiedDate = time;
646        }
647    }
648
649    /**
650     * Sets this entry's name.
651     *
652     * @param name This entry's new name.
653     */
654    public void setName(final String name) {
655        this.name = name;
656    }
657
658    /**
659     * Sets this entry's file size.
660     *
661     * @param size This entry's new file size.
662     */
663    public void setSize(final long size) {
664        this.size = size;
665    }
666
667    /**
668     * Sets the windows attributes.
669     * @param windowsAttributes the windows attributes
670     */
671    public void setWindowsAttributes(final int windowsAttributes) {
672        this.windowsAttributes = windowsAttributes;
673    }
674}