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