    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}