00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 using System;
00041 using System.IO;
00042
00043 namespace ICSharpCode.SharpZipLib.Zip
00044 {
00045
00055 public class ZipEntry : ICloneable
00056 {
00057 static int KNOWN_SIZE = 1;
00058 static int KNOWN_CSIZE = 2;
00059 static int KNOWN_CRC = 4;
00060 static int KNOWN_TIME = 8;
00061 static int KNOWN_EXTERN_ATTRIBUTES = 16;
00062
00063 ushort known = 0;
00064 int externalFileAttributes = -1;
00065
00066 ushort versionMadeBy;
00067
00068
00069 string name;
00070 ulong size;
00071 ulong compressedSize;
00072 ushort versionToExtract;
00073 uint crc;
00074 uint dosTime;
00075
00076 CompressionMethod method = CompressionMethod.Deflated;
00077 byte[] extra = null;
00078 string comment = null;
00079
00080 int flags;
00081
00082 int zipFileIndex = -1;
00083 int offset;
00084
00089 public bool IsCrypted {
00090 get {
00091 return (flags & 1) != 0;
00092 }
00093 set {
00094 if (value) {
00095 flags |= 1;
00096 } else {
00097 flags &= ~1;
00098 }
00099 }
00100 }
00101
00128 public int Flags {
00129 get {
00130 return flags;
00131 }
00132 set {
00133 flags = value;
00134 }
00135 }
00136
00137
00141 public int ZipFileIndex {
00142 get {
00143 return zipFileIndex;
00144 }
00145 set {
00146 zipFileIndex = value;
00147 }
00148 }
00149
00153 public int Offset {
00154 get {
00155 return offset;
00156 }
00157 set {
00158 if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
00159 throw new ArgumentOutOfRangeException("Offset");
00160 }
00161 offset = value;
00162 }
00163 }
00164
00165
00171 public int ExternalFileAttributes {
00172 get {
00173 if ((known & KNOWN_EXTERN_ATTRIBUTES) == 0) {
00174 return -1;
00175 } else {
00176 return externalFileAttributes;
00177 }
00178 }
00179
00180 set {
00181 externalFileAttributes = value;
00182 known |= (ushort)KNOWN_EXTERN_ATTRIBUTES;
00183 }
00184 }
00185
00191 public int VersionMadeBy {
00192 get {
00193 return versionMadeBy & 0xff;
00194 }
00195 }
00196
00234
00235 public int HostSystem {
00236 get { return (versionMadeBy >> 8) & 0xff; }
00237 }
00238
00251 public ZipEntry(string name) : this(name, 0, ZipConstants.VERSION_MADE_BY)
00252 {
00253 }
00254
00270 internal ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, ZipConstants.VERSION_MADE_BY)
00271 {
00272 }
00273
00290 internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo)
00291 {
00292 if (name == null) {
00293 throw new System.ArgumentNullException("ZipEntry name");
00294 }
00295
00296 if ( name.Length == 0 ) {
00297 throw new ArgumentException("ZipEntry name is empty");
00298 }
00299
00300 if (versionRequiredToExtract != 0 && versionRequiredToExtract < 10) {
00301 throw new ArgumentOutOfRangeException("versionRequiredToExtract");
00302 }
00303
00304 this.DateTime = System.DateTime.Now;
00305 this.name = name;
00306 this.versionMadeBy = (ushort)madeByInfo;
00307 this.versionToExtract = (ushort)versionRequiredToExtract;
00308 }
00309
00316 public ZipEntry(ZipEntry e)
00317 {
00318 known = e.known;
00319 name = e.name;
00320 size = e.size;
00321 compressedSize = e.compressedSize;
00322 crc = e.crc;
00323 dosTime = e.dosTime;
00324 method = e.method;
00325 ExtraData = e.ExtraData;
00326 comment = e.comment;
00327 versionToExtract = e.versionToExtract;
00328 versionMadeBy = e.versionMadeBy;
00329 externalFileAttributes = e.externalFileAttributes;
00330 flags = e.flags;
00331
00332 zipFileIndex = -1;
00333 offset = 0;
00334 }
00335
00361 public int Version {
00362 get {
00363 if (versionToExtract != 0) {
00364 return versionToExtract;
00365 } else {
00366 int result = 10;
00367 if (CompressionMethod.Deflated == method) {
00368 result = 20;
00369 } else if (IsDirectory == true) {
00370 result = 20;
00371 } else if (IsCrypted == true) {
00372 result = 20;
00373 } else if ((known & KNOWN_EXTERN_ATTRIBUTES) != 0 && (externalFileAttributes & 0x08) != 0) {
00374 result = 11;
00375 }
00376 return result;
00377 }
00378 }
00379 }
00380
00384 public bool RequiresZip64 {
00385 get {
00386 return (this.size > uint.MaxValue) || (this.compressedSize > uint.MaxValue);
00387 }
00388 }
00389
00393 public long DosTime {
00394 get {
00395 if ((known & KNOWN_TIME) == 0) {
00396 return 0;
00397 } else {
00398 return dosTime;
00399 }
00400 }
00401 set {
00402 this.dosTime = (uint)value;
00403 known |= (ushort)KNOWN_TIME;
00404 }
00405 }
00406
00407
00411 public DateTime DateTime {
00412 get {
00413
00414
00415 if ( dosTime == 0 ) {
00416 return DateTime.Now;
00417 }
00418 else {
00419 uint sec = 2 * (dosTime & 0x1f);
00420 uint min = (dosTime >> 5) & 0x3f;
00421 uint hrs = (dosTime >> 11) & 0x1f;
00422 uint day = (dosTime >> 16) & 0x1f;
00423 uint mon = ((dosTime >> 21) & 0xf);
00424 uint year = ((dosTime >> 25) & 0x7f) + 1980;
00425 return new System.DateTime((int)year, (int)mon, (int)day, (int)hrs, (int)min, (int)sec);
00426 }
00427 }
00428 set {
00429 DosTime = ((uint)value.Year - 1980 & 0x7f) << 25 |
00430 ((uint)value.Month) << 21 |
00431 ((uint)value.Day) << 16 |
00432 ((uint)value.Hour) << 11 |
00433 ((uint)value.Minute) << 5 |
00434 ((uint)value.Second) >> 1;
00435 }
00436 }
00437
00443 public string Name {
00444 get {
00445 return name;
00446 }
00447 }
00448
00456 static public string CleanName(string name, bool relativePath)
00457 {
00458 if (name == null) {
00459 return "";
00460 }
00461
00462 if (Path.IsPathRooted(name) == true) {
00463
00464
00465 name = name.Substring(Path.GetPathRoot(name).Length);
00466 }
00467
00468 name = name.Replace(@"\", "/");
00469
00470 if (relativePath == true) {
00471 if (name.Length > 0 && (name[0] == Path.AltDirectorySeparatorChar || name[0] == Path.DirectorySeparatorChar)) {
00472 name = name.Remove(0, 1);
00473 }
00474 } else {
00475 if (name.Length > 0 && name[0] != Path.AltDirectorySeparatorChar && name[0] != Path.DirectorySeparatorChar) {
00476 name = name.Insert(0, "/");
00477 }
00478 }
00479 return name;
00480 }
00481
00490 static public string CleanName(string name)
00491 {
00492 return CleanName(name, true);
00493 }
00494
00504 public long Size {
00505 get {
00506 return (known & KNOWN_SIZE) != 0 ? (long)size : -1L;
00507 }
00508 set {
00509 if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
00510 throw new ArgumentOutOfRangeException("size");
00511 }
00512 this.size = (ulong)value;
00513 this.known |= (ushort)KNOWN_SIZE;
00514 }
00515 }
00516
00526 public long CompressedSize {
00527 get {
00528 return (known & KNOWN_CSIZE) != 0 ? (long)compressedSize : -1L;
00529 }
00530 set {
00531 if (((ulong)value & 0xffffffff00000000L) != 0) {
00532 throw new ArgumentOutOfRangeException();
00533 }
00534 this.compressedSize = (ulong)value;
00535 this.known |= (ushort)KNOWN_CSIZE;
00536 }
00537 }
00538
00548 public long Crc {
00549 get {
00550 return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
00551 }
00552 set {
00553 if (((ulong)crc & 0xffffffff00000000L) != 0) {
00554 throw new ArgumentOutOfRangeException();
00555 }
00556 this.crc = (uint)value;
00557 this.known |= (ushort)KNOWN_CRC;
00558 }
00559 }
00560
00569 public CompressionMethod CompressionMethod {
00570 get {
00571 return method;
00572 }
00573 set {
00574 this.method = value;
00575 }
00576 }
00577
00587 public byte[] ExtraData {
00588 get {
00589 return extra;
00590 }
00591 set {
00592 if (value == null) {
00593 this.extra = null;
00594 return;
00595 }
00596
00597 if (value.Length > 0xffff) {
00598 throw new System.ArgumentOutOfRangeException();
00599 }
00600
00601 this.extra = new byte[value.Length];
00602 Array.Copy(value, 0, this.extra, 0, value.Length);
00603
00604 try {
00605 int pos = 0;
00606 while (pos < extra.Length) {
00607 int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
00608 int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
00609
00610 if (len < 0 || pos + len > extra.Length) {
00611
00612
00613
00614 break;
00615 }
00616
00617 if (sig == 0x5455) {
00618
00619 int flags = extra[pos];
00620
00621
00622 if ((flags & 1) != 0 && len >= 5) {
00623 int iTime = ((extra[pos+1] & 0xff) |
00624 (extra[pos + 2] & 0xff) << 8 |
00625 (extra[pos + 3] & 0xff) << 16 |
00626 (extra[pos + 4] & 0xff) << 24);
00627
00628 DateTime = (new DateTime ( 1970, 1, 1, 0, 0, 0 ) + new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime ();
00629 known |= (ushort)KNOWN_TIME;
00630 }
00631 } else if (sig == 0x0001) {
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 }
00642 pos += len;
00643 }
00644 } catch (Exception) {
00645
00646 return;
00647 }
00648 }
00649 }
00650
00651
00661 public string Comment {
00662 get {
00663 return comment;
00664 }
00665 set {
00666
00667
00668
00669 if (value != null && value.Length > 0xffff) {
00670 throw new ArgumentOutOfRangeException();
00671 }
00672 this.comment = value;
00673 }
00674 }
00675
00682 public bool IsDirectory {
00683 get {
00684 int nlen = name.Length;
00685 bool result = nlen > 0 && name[nlen - 1] == '/';
00686
00687 if (result == false && (known & KNOWN_EXTERN_ATTRIBUTES) != 0) {
00688 if (HostSystem == 0 && (ExternalFileAttributes & 16) != 0) {
00689 result = true;
00690 }
00691 }
00692 return result;
00693 }
00694 }
00695
00703 public bool IsFile {
00704 get {
00705 bool result = !IsDirectory;
00706
00707
00708 if ( result && (known & KNOWN_EXTERN_ATTRIBUTES) != 0) {
00709 if (HostSystem == 0 && (ExternalFileAttributes & 8) != 0) {
00710 result = false;
00711 }
00712 }
00713 return result;
00714 }
00715 }
00716
00720 public object Clone()
00721 {
00722 return this.MemberwiseClone();
00723 }
00724
00728 public override string ToString()
00729 {
00730 return name;
00731 }
00732 }
00733 }