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