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