1:   // ZipEntry.cs
2:   // Copyright (C) 2001 Mike Krueger
3:   //
4:   // This file was translated from java, it was part of the GNU Classpath
5:   // Copyright (C) 2001 Free Software Foundation, Inc.
6:   //
7:   // This program is free software; you can redistribute it and/or
8:   // modify it under the terms of the GNU General Public License
9:   // as published by the Free Software Foundation; either version 2
10:   // of the License, or (at your option) any later version.
11:   //
12:   // This program is distributed in the hope that it will be useful,
13:   // but WITHOUT ANY WARRANTY; without even the implied warranty of
14:   // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15:   // GNU General Public License for more details.
16:   //
17:   // You should have received a copy of the GNU General Public License
18:   // along with this program; if not, write to the Free Software
19:   // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20:   //
21:   // Linking this library statically or dynamically with other modules is
22:   // making a combined work based on this library.  Thus, the terms and
23:   // conditions of the GNU General Public License cover the whole
24:   // combination.
25:   // 
26:   // As a special exception, the copyright holders of this library give you
27:   // permission to link this library with independent modules to produce an
28:   // executable, regardless of the license terms of these independent
29:   // modules, and to copy and distribute the resulting executable under
30:   // terms of your choice, provided that you also meet, for each linked
31:   // independent module, the terms and conditions of the license of that
32:   // module.  An independent module is a module which is not derived from
33:   // or based on this library.  If you modify this library, you may extend
34:   // this exception to your version of the library, but you are not
35:   // obligated to do so.  If you do not wish to do so, delete this
36:   // exception statement from your version.
37:  
38:   using System;
39:  
40:   namespace ICSharpCode.SharpZipLib.Zip {
41:       
42:       public enum CompressionMethod
43:       {
44:           Stored   0,
45:           Deflated 8,
46:       }
47:       
48:       /// <summary>
49:       /// This class represents a member of a zip archive.  ZipFile and
50:       /// ZipInputStream will give you instances of this class as information
51:       /// about the members in an archive.  On the other hand ZipOutputStream
52:       /// needs an instance of this class to create a new member.
53:       ///
54:       /// author of the original java version : Jochen Hoenicke
55:       /// </summary>
56:       public class ZipEntry : ICloneable
57:       {
58:           static int KNOWN_SIZE   1;
59:           static int KNOWN_CSIZE  2;
60:           static int KNOWN_CRC    4;
61:           static int KNOWN_TIME   8;
62:           
63:           DateTime cal DateTime.Now;
64:           
65:           string name;
66:           uint   size;
67:           ushort version;
68:           uint   compressedSize;
69:           int    crc;
70:           
71:           ushort known 0;
72:           CompressionMethod  method CompressionMethod.Deflated;
73:           byte[] extra null;
74:           string comment null;
75:           
76:           public int zipFileIndex = -1;  /* used by ZipFile */
77:           public int flags;              /* used by ZipOutputStream */
78:           public int offset;             /* used by ZipFile and ZipOutputStream */
79:           
80:           /// <summary>
81:           /// Creates a zip entry with the given name.
82:           /// </summary>
83:           /// <param name="name">
84:           /// the name. May include directory components separated by '/'.
85:           /// </param>
86:           public ZipEntry(string name)
87:           {
88:               if (name == null) {
89:                   throw new System.ArgumentNullException("name");
90:               }
91:               this.name name;
92:           }
93:           
94:           /// <summary>
95:           /// Creates a copy of the given zip entry.
96:           /// </summary>
97:           /// <param name="e">
98:           /// the entry to copy.
99:           /// </param>
100:           public ZipEntry(ZipEntry e)
101:           {
102:               name e.name;
103:               known e.known;
104:               size e.size;
105:               compressedSize e.compressedSize;
106:               crc e.crc;
107:   //            time = e.time;
108:               method e.method;
109:               extra e.extra;
110:               comment e.comment;
111:           }
112:           
113:           public ushort Version {
114:               get {
115:                   return version;
116:               }
117:               set {
118:                   version value;
119:               }
120:           }
121:           
122:           public int DosTime {
123:               get {
124:   //                if ((known & KNOWN_TIME) == 0) {
125:   //                    return 0;
126:   //                }
127:                   lock (this) {
128:                       return (cal.Year 1980 0x7f) << 25 |
129:                              (cal.Month 1) << 21 
130:                              (cal.Day ) << 16 
131:                              (cal.Hour) << 11 |
132:                              (cal.Minute) << |
133:                              (cal.Second) >> 1;
134:                   }
135:               }
136:               set {
137:                   // Guard against invalid or missing date causing
138:                   // IndexOutOfBoundsException.
139:                   try {
140:                       lock (this) {
141:                           cal CalculateDateTime(value);
142:   //                        time = (int) (cal.Millisecond / 1000L);
143:                       }
144:                       known |= (ushort)KNOWN_TIME;
145:                   catch (Exception) {
146:                       /* Ignore illegal time stamp */
147:                       known &= (ushort)~KNOWN_TIME;
148:                   }
149:               }
150:           }
151:           
152:           /// <summary>
153:           /// Gets/Sets the time of last modification of the entry.
154:           /// </summary>
155:           public DateTime DateTime {
156:               get {
157:                   return cal;
158:               }
159:               set {
160:                   lock (this) {
161:                       cal value;
162:   //                    time = (int) (cal.Millisecond / 1000L);                    
163:                   }
164:                   known |= (ushort)KNOWN_TIME;
165:               }
166:           }
167:               
168:           /// <summary>
169:           /// Returns the entry name.  The path components in the entry are
170:           /// always separated by slashes ('/').
171:           /// </summary>
172:           public string Name {
173:               get {
174:                   return name;
175:               }
176:           }
177:           
178:   //        /// <summary>
179:   //        /// Gets/Sets the time of last modification of the entry.
180:   //        /// </summary>
181:   //        /// <returns>
182:   //        /// the time of last modification of the entry, or -1 if unknown.
183:   //        /// </returns>
184:   //        public long Time {
185:   //            get {
186:   //                return (known & KNOWN_TIME) != 0 ? time * 1000L : -1;
187:   //            }
188:   //            set {
189:   //                this.time = (int) (value / 1000L);
190:   //                this.known |= (ushort)KNOWN_TIME;
191:   //            }
192:   //        }
193:           
194:           /// <summary>
195:           /// Gets/Sets the size of the uncompressed data.
196:           /// </summary>
197:           /// <exception cref="System.ArgumentOutOfRangeException">
198:           /// if size is not in 0..0xffffffffL
199:           /// </exception>
200:           /// <returns>
201:           /// the size or -1 if unknown.
202:           /// </returns>
203:           public long Size {
204:               get {
205:                   return (known KNOWN_SIZE) != ? (long)size : -1L;
206:               }
207:               set {
208:                   if (((ulong)value 0xFFFFFFFF00000000L) != 0) {
209:                       throw new ArgumentOutOfRangeException("size");
210:                   }
211:                   this.size  = (uint)value;
212:                   this.known |= (ushort)KNOWN_SIZE;
213:               }
214:           }
215:           
216:           /// <summary>
217:           /// Gets/Sets the size of the compressed data.
218:           /// </summary>
219:           /// <exception cref="System.ArgumentOutOfRangeException">
220:           /// if csize is not in 0..0xffffffffL
221:           /// </exception>
222:           /// <returns>
223:           /// the size or -1 if unknown.
224:           /// </returns>
225:           public long CompressedSize {
226:               get {
227:                   return (known KNOWN_CSIZE) != ? (long)compressedSize : -1L;
228:               }
229:               set {
230:                   if (((ulong)value 0xffffffff00000000L) != 0) {
231:                       throw new ArgumentOutOfRangeException();
232:                   }
233:                   this.compressedSize = (uint)value;
234:                   this.known |= (ushort)KNOWN_CSIZE;
235:               }
236:           }
237:           
238:           /// <summary>
239:           /// Gets/Sets the crc of the uncompressed data.
240:           /// </summary>
241:           /// <exception cref="System.ArgumentOutOfRangeException">
242:           /// if crc is not in 0..0xffffffffL
243:           /// </exception>
244:           /// <returns>
245:           /// the crc or -1 if unknown.
246:           /// </returns>
247:           public long Crc {
248:               get {
249:                   return (known KNOWN_CRC) != crc 0xffffffffL -1L;
250:               }
251:               set {
252:                   if (((ulong)crc 0xffffffff00000000L) != 0) {
253:                       throw new Exception();
254:                   }
255:                   this.crc = (int)value;
256:                   this.known |= (ushort)KNOWN_CRC;
257:               }
258:           }
259:           
260:           /// <summary>
261:           /// Gets/Sets the compression method. Only DEFLATED and STORED are supported.
262:           /// </summary>
263:           /// <exception cref="System.ArgumentOutOfRangeException">
264:           /// if method is not supported.
265:           /// </exception>
266:           /// <returns>
267:           /// the compression method or -1 if unknown.
268:           /// </returns>
269:           /// <see cref="ZipOutputStream.DEFLATED"/>
270:           /// <see cref="ZipOutputStream.STORED"/>
271:           public CompressionMethod CompressionMethod {
272:               get {
273:                   return method;
274:               }
275:               set {
276:                   this.method value;
277:               }
278:           }
279:           
280:           /// <summary>
281:           /// Gets/Sets the extra data.
282:           /// </summary>
283:           /// <exception cref="System.ArgumentOutOfRangeException">
284:           /// if extra is longer than 0xffff bytes.
285:           /// </exception>
286:           /// <returns>
287:           /// the extra data or null if not set.
288:           /// </returns>
289:           public byte[] ExtraData {
290:               get {
291:                   return extra;
292:               }
293:               set {
294:                   if (value == null) {
295:                       this.extra null;
296:                       return;
297:                   }
298:                   
299:                   if (value.Length 0xffff) {
300:                       throw new System.ArgumentOutOfRangeException();
301:                   }
302:                   this.extra value;
303:                   try {
304:                       int pos 0;
305:                       while (pos extra.Length) {
306:                           int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
307:                           int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
308:                           if (sig == 0x5455) {
309:                               /* extended time stamp, unix format by Rainer Prem <Rainer@Prem.de> */
310:                               int flags extra[pos];
311:                               if ((flags 1) != 0) {
312:                                   int iTime = ((extra[pos+1] & 0xff)       |
313:                                                (extra[pos+2] & 0xff) << 8  |
314:                                                (extra[pos+3] & 0xff) << 16 |
315:                                                (extra[pos+4] & 0xff) << 24);
316:                                   
317:                                   cal = (new DateTime 19701100) + 
318:                                          new TimeSpan 000iTime)).ToLocalTime ();
319:                                   known |= (ushort)KNOWN_TIME;
320:                               }
321:                           }
322:                           pos += len;
323:                       }
324:                   catch (Exception) {
325:                       /* be lenient */
326:                       return;
327:                   }
328:               }
329:           }
330:           
331:           /// <summary>
332:           /// Gets/Sets the entry comment.
333:           /// </summary>
334:           /// <exception cref="System.ArgumentOutOfRangeException">
335:           /// if comment is longer than 0xffff.
336:           /// </exception>
337:           /// <returns>
338:           /// the comment or null if not set.
339:           /// </returns>
340:           public string Comment {
341:               get {
342:                   return comment;
343:               }
344:               set {
345:                   if (value.Length 0xffff) {
346:                       throw new ArgumentOutOfRangeException();
347:                   }
348:                   this.comment value;
349:               }
350:           }
351:           
352:           /// <summary>
353:           /// Gets true, if the entry is a directory.  This is solely
354:           /// determined by the name, a trailing slash '/' marks a directory.
355:           /// </summary>
356:           public bool IsDirectory {
357:               get {
358:                   int nlen name.Length;
359:                   return nlen && name[nlen 1] == '/';
360:               }
361:           }
362:           
363:           /// <summary>
364:           /// Creates a copy of this zip entry.
365:           /// </summary>
366:           public object Clone()
367:           {
368:               return this.MemberwiseClone();
369:           }
370:           
371:           /// <summary>
372:           /// Gets the string representation of this ZipEntry.  This is just
373:           /// the name as returned by getName().
374:           /// </summary>
375:           public override string ToString()
376:           {
377:               return name;
378:           }
379:           
380:           DateTime CalculateDateTime(int dosTime)
381:           {
382:               int sec * (dosTime 0x1f);
383:               int min = (dosTime >> 5) & 0x3f;
384:               int hrs = (dosTime >> 11) & 0x1f;
385:               int day = (dosTime >> 16) & 0x1f;
386:               int mon = ((dosTime >> 21) & 0xf);
387:               int year = ((dosTime >> 25) & 0x7f) + 1980/* since 1900 */
388: