    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.util.Calendar;
    021import java.util.Collections;
    022import java.util.Date;
    023import java.util.LinkedList;
    024import java.util.TimeZone;
    025
    026import org.apache.commons.compress.archivers.ArchiveEntry;
    027
    028/**
    029 * An entry in a 7z archive.
    030 *
    031 * @NotThreadSafe
    032 * @since 1.6
    033 */
    034public class SevenZArchiveEntry implements ArchiveEntry {
    035    private String name;
    036    private boolean hasStream;
    037    private boolean isDirectory;
    038    private boolean isAntiItem;
    039    private boolean hasCreationDate;
    040    private boolean hasLastModifiedDate;
    041    private boolean hasAccessDate;
    042    private long creationDate;
    043    private long lastModifiedDate;
    044    private long accessDate;
    045    private boolean hasWindowsAttributes;
    046    private int windowsAttributes;
    047    private boolean hasCrc;
    048    private long crc, compressedCrc;
    049    private long size, compressedSize;
    050    private Iterable<? extends SevenZMethodConfiguration> contentMethods;
    051
    052    public SevenZArchiveEntry() {
    053    }
    054
    055    /**
    056     * Get this entry's name.
    057     *
    058     * @return This entry's name.
    059     */
    060    @Override
    061    public String getName() {
    062        return name;
    063    }
    064
    065    /**
    066     * Set this entry's name.
    067     *
    068     * @param name This entry's new name.
    069     */
    070    public void setName(final String name) {
    071        this.name = name;
    072    }
    073
    074    /**
    075     * Whether there is any content associated with this entry.
    076     * @return whether there is any content associated with this entry.
    077     */
    078    public boolean hasStream() {
    079        return hasStream;
    080    }
    081
    082    /**
    083     * Sets whether there is any content associated with this entry.
    084     * @param hasStream whether there is any content associated with this entry.
    085     */
    086    public void setHasStream(final boolean hasStream) {
    087        this.hasStream = hasStream;
    088    }
    089
    090    /**
    091     * Return whether or not this entry represents a directory.
    092     *
    093     * @return True if this entry is a directory.
    094     */
    095    @Override
    096    public boolean isDirectory() {
    097        return isDirectory;
    098    }
    099
    100    /**
    101     * Sets whether or not this entry represents a directory.
    102     *
    103     * @param isDirectory True if this entry is a directory.
    104     */
    105    public void setDirectory(final boolean isDirectory) {
    106        this.isDirectory = isDirectory;
    107    }
    108
    109    /**
    110     * Indicates whether this is an "anti-item" used in differential backups,
    111     * meaning it should delete the same file from a previous backup.
    112     * @return true if it is an anti-item, false otherwise
    113     */
    114    public boolean isAntiItem() {
    115        return isAntiItem;
    116    }
    117
    118    /**
    119     * Sets whether this is an "anti-item" used in differential backups,
    120     * meaning it should delete the same file from a previous backup.
    121     * @param isAntiItem true if it is an anti-item, false otherwise
    122     */
    123    public void setAntiItem(final boolean isAntiItem) {
    124        this.isAntiItem = isAntiItem;
    125    }
    126
    127    /**
    128     * Returns whether this entry has got a creation date at all.
    129     * @return whether the entry has got a creation date
    130     */
    131    public boolean getHasCreationDate() {
    132        return hasCreationDate;
    133    }
    134
    135    /**
    136     * Sets whether this entry has got a creation date at all.
    137     * @param hasCreationDate whether the entry has got a creation date
    138     */
    139    public void setHasCreationDate(final boolean hasCreationDate) {
    140        this.hasCreationDate = hasCreationDate;
    141    }
    142
    143    /**
    144     * Gets the creation date.
    145     * @throws UnsupportedOperationException if the entry hasn't got a
    146     * creation date.
    147     * @return the creation date
    148     */
    149    public Date getCreationDate() {
    150        if (hasCreationDate) {
    151            return ntfsTimeToJavaTime(creationDate);
    152        }
    153        throw new UnsupportedOperationException(
    154                "The entry doesn't have this timestamp");
    155    }
    156
    157    /**
    158     * Sets the creation date using NTFS time (100 nanosecond units
    159     * since 1 January 1601)
    160     * @param ntfsCreationDate the creation date
    161     */
    162    public void setCreationDate(final long ntfsCreationDate) {
    163        this.creationDate = ntfsCreationDate;
    164    }
    165
    166    /**
    167     * Sets the creation date,
    168     * @param creationDate the creation date
    169     */
    170    public void setCreationDate(final Date creationDate) {
    171        hasCreationDate = creationDate != null;
    172        if (hasCreationDate) {
    173            this.creationDate = javaTimeToNtfsTime(creationDate);
    174        }
    175    }
    176
    177    /**
    178     * Returns whether this entry has got a last modified date at all.
    179     * @return whether this entry has got a last modified date at all
    180     */
    181    public boolean getHasLastModifiedDate() {
    182        return hasLastModifiedDate;
    183    }
    184
    185    /**
    186     * Sets whether this entry has got a last modified date at all.
    187     * @param hasLastModifiedDate whether this entry has got a last
    188     * modified date at all
    189     */
    190    public void setHasLastModifiedDate(final boolean hasLastModifiedDate) {
    191        this.hasLastModifiedDate = hasLastModifiedDate;
    192    }
    193
    194    /**
    195     * Gets the last modified date.
    196     * @throws UnsupportedOperationException if the entry hasn't got a
    197     * last modified date.
    198     * @return the last modified date
    199     */
    200    @Override
    201    public Date getLastModifiedDate() {
    202        if (hasLastModifiedDate) {
    203            return ntfsTimeToJavaTime(lastModifiedDate);
    204        }
    205        throw new UnsupportedOperationException(
    206                "The entry doesn't have this timestamp");
    207    }
    208
    209    /**
    210     * Sets the last modified date using NTFS time (100 nanosecond
    211     * units since 1 January 1601)
    212     * @param ntfsLastModifiedDate the last modified date
    213     */
    214    public void setLastModifiedDate(final long ntfsLastModifiedDate) {
    215        this.lastModifiedDate = ntfsLastModifiedDate;
    216    }
    217
    218    /**
    219     * Sets the last modified date,
    220     * @param lastModifiedDate the last modified date
    221     */
    222    public void setLastModifiedDate(final Date lastModifiedDate) {
    223        hasLastModifiedDate = lastModifiedDate != null;
    224        if (hasLastModifiedDate) {
    225            this.lastModifiedDate = javaTimeToNtfsTime(lastModifiedDate);
    226        }
    227    }
    228
    229    /**
    230     * Returns whether this entry has got an access date at all.
    231     * @return whether this entry has got an access date at all.
    232     */
    233    public boolean getHasAccessDate() {
    234        return hasAccessDate;
    235    }
    236
    237    /**
    238     * Sets whether this entry has got an access date at all.
    239     * @param hasAcessDate whether this entry has got an access date at all.
    240     */
    241    public void setHasAccessDate(final boolean hasAcessDate) {
    242        this.hasAccessDate = hasAcessDate;
    243    }
    244
    245    /**
    246     * Gets the access date.
    247     * @throws UnsupportedOperationException if the entry hasn't got a
    248     * access date.
    249     * @return the access date
    250     */
    251    public Date getAccessDate() {
    252        if (hasAccessDate) {
    253            return ntfsTimeToJavaTime(accessDate);
    254        }
    255        throw new UnsupportedOperationException(
    256                "The entry doesn't have this timestamp");
    257    }
    258
    259    /**
    260     * Sets the access date using NTFS time (100 nanosecond units
    261     * since 1 January 1601)
    262     * @param ntfsAccessDate the access date
    263     */
    264    public void setAccessDate(final long ntfsAccessDate) {
    265        this.accessDate = ntfsAccessDate;
    266    }
    267
    268    /**
    269     * Sets the access date,
    270     * @param accessDate the access date
    271     */
    272    public void setAccessDate(final Date accessDate) {
    273        hasAccessDate = accessDate != null;
    274        if (hasAccessDate) {
    275            this.accessDate = javaTimeToNtfsTime(accessDate);
    276        }
    277    }
    278
    279    /**
    280     * Returns whether this entry has windows attributes.
    281     * @return whether this entry has windows attributes.
    282     */
    283    public boolean getHasWindowsAttributes() {
    284        return hasWindowsAttributes;
    285    }
    286
    287    /**
    288     * Sets whether this entry has windows attributes.
    289     * @param hasWindowsAttributes whether this entry has windows attributes.
    290     */
    291    public void setHasWindowsAttributes(final boolean hasWindowsAttributes) {
    292        this.hasWindowsAttributes = hasWindowsAttributes;
    293    }
    294
    295    /**
    296     * Gets the windows attributes.
    297     * @return the windows attributes
    298     */
    299    public int getWindowsAttributes() {
    300        return windowsAttributes;
    301    }
    302
    303    /**
    304     * Sets the windows attributes.
    305     * @param windowsAttributes the windows attributes
    306     */
    307    public void setWindowsAttributes(final int windowsAttributes) {
    308        this.windowsAttributes = windowsAttributes;
    309    }
    310
    311    /**
    312     * Returns whether this entry has got a crc.
    313     *
    314     * <p>In general entries without streams don't have a CRC either.</p>
    315     * @return whether this entry has got a crc.
    316     */
    317    public boolean getHasCrc() {
    318        return hasCrc;
    319    }
    320
    321    /**
    322     * Sets whether this entry has got a crc.
    323     * @param hasCrc whether this entry has got a crc.
    324     */
    325    public void setHasCrc(final boolean hasCrc) {
    326        this.hasCrc = hasCrc;
    327    }
    328
    329    /**
    330     * Gets the CRC.
    331     * @deprecated use getCrcValue instead.
    332     * @return the CRC
    333     */
    334    @Deprecated
    335    public int getCrc() {
    336        return (int) crc;
    337    }
    338
    339    /**
    340     * Sets the CRC.
    341     * @deprecated use setCrcValue instead.
    342     * @param crc the CRC
    343     */
    344    @Deprecated
    345    public void setCrc(final int crc) {
    346        this.crc = crc;
    347    }
    348
    349    /**
    350     * Gets the CRC.
    351     * @since Compress 1.7
    352     * @return the CRC
    353     */
    354    public long getCrcValue() {
    355        return crc;
    356    }
    357
    358    /**
    359     * Sets the CRC.
    360     * @since Compress 1.7
    361     * @param crc the CRC
    362     */
    363    public void setCrcValue(final long crc) {
    364        this.crc = crc;
    365    }
    366
    367    /**
    368     * Gets the compressed CRC.
    369     * @deprecated use getCompressedCrcValue instead.
    370     * @return the compressed CRC
    371     */
    372    @Deprecated
    373    int getCompressedCrc() {
    374        return (int) compressedCrc;
    375    }
    376
    377    /**
    378     * Sets the compressed CRC.
    379     * @deprecated use setCompressedCrcValue instead.
    380     * @param crc the CRC
    381     */
    382    @Deprecated
    383    void setCompressedCrc(final int crc) {
    384        this.compressedCrc = crc;
    385    }
    386
    387    /**
    388     * Gets the compressed CRC.
    389     * @since Compress 1.7
    390     * @return the CRC
    391     */
    392    long getCompressedCrcValue() {
    393        return compressedCrc;
    394    }
    395
    396    /**
    397     * Sets the compressed CRC.
    398     * @since Compress 1.7
    399     * @param crc the CRC
    400     */
    401    void setCompressedCrcValue(final long crc) {
    402        this.compressedCrc = crc;
    403    }
    404
    405    /**
    406     * Get this entry's file size.
    407     *
    408     * @return This entry's file size.
    409     */
    410    @Override
    411    public long getSize() {
    412        return size;
    413    }
    414
    415    /**
    416     * Set this entry's file size.
    417     *
    418     * @param size This entry's new file size.
    419     */
    420    public void setSize(final long size) {
    421        this.size = size;
    422    }
    423
    424    /**
    425     * Get this entry's compressed file size.
    426     *
    427     * @return This entry's compressed file size.
    428     */
    429    long getCompressedSize() {
    430        return compressedSize;
    431    }
    432
    433    /**
    434     * Set this entry's compressed file size.
    435     *
    436     * @param size This entry's new compressed file size.
    437     */
    438    void setCompressedSize(final long size) {
    439        this.compressedSize = size;
    440    }
    441
    442    /**
    443     * Sets the (compression) methods to use for entry's content - the
    444     * default is LZMA2.
    445     *
    446     * <p>Currently only {@link SevenZMethod#COPY}, {@link
    447     * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link
    448     * SevenZMethod#DEFLATE} are supported when writing archives.</p>
    449     *
    450     * <p>The methods will be consulted in iteration order to create
    451     * the final output.</p>
    452     *
    453     * @param methods the methods to use for the content
    454     * @since 1.8
    455     */
    456    public void setContentMethods(final Iterable<? extends SevenZMethodConfiguration> methods) {
    457        if (methods != null) {
    458            final LinkedList<SevenZMethodConfiguration> l = new LinkedList<>();
    459            for (final SevenZMethodConfiguration m : methods) {
    460                l.addLast(m);
    461            }
    462            contentMethods = Collections.unmodifiableList(l);
    463        } else {
    464            contentMethods = null;
    465        }
    466    }
    467
    468    /**
    469     * Gets the (compression) methods to use for entry's content - the
    470     * default is LZMA2.
    471     *
    472     * <p>Currently only {@link SevenZMethod#COPY}, {@link
    473     * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link
    474     * SevenZMethod#DEFLATE} are supported when writing archives.</p>
    475     *
    476     * <p>The methods will be consulted in iteration order to create
    477     * the final output.</p>
    478     *
    479     * @since 1.8
    480     * @return the methods to use for the content
    481     */
    482    public Iterable<? extends SevenZMethodConfiguration> getContentMethods() {
    483        return contentMethods;
    484    }
    485
    486    /**
    487     * Converts NTFS time (100 nanosecond units since 1 January 1601)
    488     * to Java time.
    489     * @param ntfsTime the NTFS time in 100 nanosecond units
    490     * @return the Java time
    491     */
    492    public static Date ntfsTimeToJavaTime(final long ntfsTime) {
    493        final Calendar ntfsEpoch = Calendar.getInstance();
    494        ntfsEpoch.setTimeZone(TimeZone.getTimeZone("GMT+0"));
    495        ntfsEpoch.set(1601, 0, 1, 0, 0, 0);
    496        ntfsEpoch.set(Calendar.MILLISECOND, 0);
    497        final long realTime = ntfsEpoch.getTimeInMillis() + (ntfsTime / (10*1000));
    498        return new Date(realTime);
    499    }
    500
    501    /**
    502     * Converts Java time to NTFS time.
    503     * @param date the Java time
    504     * @return the NTFS time
    505     */
    506    public static long javaTimeToNtfsTime(final Date date) {
    507        final Calendar ntfsEpoch = Calendar.getInstance();
    508        ntfsEpoch.setTimeZone(TimeZone.getTimeZone("GMT+0"));
    509        ntfsEpoch.set(1601, 0, 1, 0, 0, 0);
    510        ntfsEpoch.set(Calendar.MILLISECOND, 0);
    511        return ((date.getTime() - ntfsEpoch.getTimeInMillis())* 1000 * 10);
    512    }
    513}