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.Text;
00042 using System.IO;
00043
00044 using ICSharpCode.SharpZipLib.Checksums;
00045 using ICSharpCode.SharpZipLib.Zip.Compression;
00046 using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
00047 using ICSharpCode.SharpZipLib.Encryption;
00048
00049 namespace ICSharpCode.SharpZipLib.Zip
00050 {
00097 public class ZipInputStream : InflaterInputStream
00098 {
00099
00100 delegate int ReaderDelegate(byte[] b, int offset, int length);
00101
00105 ReaderDelegate internalReader;
00106
00107 Crc32 crc = new Crc32();
00108 ZipEntry entry = null;
00109
00110 long size;
00111 int method;
00112 int flags;
00113 string password = null;
00114
00118 public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(true))
00119 {
00120 internalReader = new ReaderDelegate(InitialRead);
00121 }
00122
00123
00127 public string Password
00128 {
00129 get {
00130 return password;
00131 }
00132 set {
00133 password = value;
00134 }
00135 }
00136
00137
00145 public bool CanDecompressEntry {
00146 get {
00147 return entry != null && entry.Version <= ZipConstants.VERSION_MADE_BY;
00148 }
00149 }
00150
00167 public ZipEntry GetNextEntry()
00168 {
00169 if (crc == null) {
00170 throw new InvalidOperationException("Closed.");
00171 }
00172
00173 if (entry != null) {
00174 CloseEntry();
00175 }
00176
00177 int header = inputBuffer.ReadLeInt();
00178
00179 if (header == ZipConstants.CENSIG ||
00180 header == ZipConstants.ENDSIG ||
00181 header == ZipConstants.CENDIGITALSIG ||
00182 header == ZipConstants.CENSIG64) {
00183
00184 Close();
00185 return null;
00186 }
00187
00188
00189
00190 if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) {
00191 header = inputBuffer.ReadLeInt();
00192 }
00193
00194 if (header != ZipConstants.LOCSIG) {
00195 throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
00196 }
00197
00198 short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
00199
00200 flags = inputBuffer.ReadLeShort();
00201 method = inputBuffer.ReadLeShort();
00202 uint dostime = (uint)inputBuffer.ReadLeInt();
00203 int crc2 = inputBuffer.ReadLeInt();
00204 csize = inputBuffer.ReadLeInt();
00205 size = inputBuffer.ReadLeInt();
00206 int nameLen = inputBuffer.ReadLeShort();
00207 int extraLen = inputBuffer.ReadLeShort();
00208
00209 bool isCrypted = (flags & 1) == 1;
00210
00211 byte[] buffer = new byte[nameLen];
00212 inputBuffer.ReadRawBuffer(buffer);
00213
00214 string name = ZipConstants.ConvertToString(buffer);
00215
00216 entry = new ZipEntry(name, versionRequiredToExtract);
00217 entry.Flags = flags;
00218
00219 if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size))) {
00220 throw new ZipException("Stored, but compressed != uncompressed");
00221 }
00222
00223 if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated) {
00224 throw new ZipException("Unknown compression method " + method);
00225 }
00226
00227 entry.CompressionMethod = (CompressionMethod)method;
00228
00229 if ((flags & 8) == 0) {
00230 entry.Crc = crc2 & 0xFFFFFFFFL;
00231 entry.Size = size & 0xFFFFFFFFL;
00232 entry.CompressedSize = csize & 0xFFFFFFFFL;
00233 } else {
00234
00235
00236
00237 if (crc2 != 0) {
00238 entry.Crc = crc2 & 0xFFFFFFFFL;
00239 }
00240
00241 if (size != 0) {
00242 entry.Size = size & 0xFFFFFFFFL;
00243 }
00244 if (csize != 0) {
00245 entry.CompressedSize = csize & 0xFFFFFFFFL;
00246 }
00247 }
00248
00249 entry.DosTime = dostime;
00250
00251 if (extraLen > 0) {
00252 byte[] extra = new byte[extraLen];
00253 inputBuffer.ReadRawBuffer(extra);
00254 entry.ExtraData = extra;
00255 }
00256
00257 internalReader = new ReaderDelegate(InitialRead);
00258 return entry;
00259 }
00260
00261
00262 void ReadDataDescriptor()
00263 {
00264 if (inputBuffer.ReadLeInt() != ZipConstants.EXTSIG) {
00265 throw new ZipException("Data descriptor signature not found");
00266 }
00267
00268 entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;
00269 csize = inputBuffer.ReadLeInt();
00270 size = inputBuffer.ReadLeInt();
00271
00272 entry.Size = size & 0xFFFFFFFFL;
00273 entry.CompressedSize = csize & 0xFFFFFFFFL;
00274 }
00275
00285 public void CloseEntry()
00286 {
00287 if (crc == null) {
00288 throw new InvalidOperationException("Closed.");
00289 }
00290
00291 if (entry == null) {
00292 return;
00293 }
00294
00295 if (method == (int)CompressionMethod.Deflated) {
00296 if ((flags & 8) != 0) {
00297
00298 byte[] tmp = new byte[2048];
00299 while (Read(tmp, 0, tmp.Length) > 0)
00300 ;
00301
00302 return;
00303 }
00304 csize -= inf.TotalIn;
00305 inputBuffer.Available -= inf.RemainingInput;
00306 }
00307
00308 if (inputBuffer.Available > csize && csize >= 0) {
00309 inputBuffer.Available = (int)((long)inputBuffer.Available - csize);
00310 } else {
00311 csize -= inputBuffer.Available;
00312 inputBuffer.Available = 0;
00313 while (csize != 0) {
00314 int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);
00315
00316 if (skipped <= 0) {
00317 throw new ZipException("Zip archive ends early.");
00318 }
00319
00320 csize -= skipped;
00321 }
00322 }
00323
00324 size = 0;
00325 crc.Reset();
00326 if (method == (int)CompressionMethod.Deflated) {
00327 inf.Reset();
00328 }
00329 entry = null;
00330 }
00331
00336 public override int Available {
00337 get {
00338 return entry != null ? 1 : 0;
00339 }
00340 }
00341
00354 public override int ReadByte()
00355 {
00356 byte[] b = new byte[1];
00357 if (Read(b, 0, 1) <= 0) {
00358 return -1;
00359 }
00360 return b[0] & 0xff;
00361 }
00362
00363
00364
00365 int InitialRead(byte[] destination, int offset, int count)
00366 {
00367 if (entry.Version > ZipConstants.VERSION_MADE_BY) {
00368 throw new ZipException("Libray cannot extract this entry version required (" + entry.Version.ToString() + ")");
00369 }
00370
00371
00372 if (entry.IsCrypted) {
00373
00374 if (password == null) {
00375 throw new ZipException("No password set.");
00376 }
00377
00378
00379 PkzipClassicManaged managed = new PkzipClassicManaged();
00380 byte[] key = PkzipClassic.GenerateKeys(Encoding.ASCII.GetBytes(password));
00381
00382 inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
00383
00384 byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
00385 inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CRYPTO_HEADER_SIZE);
00386
00387 if ((flags & 8) == 0) {
00388 if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) {
00389 throw new ZipException("Invalid password");
00390 }
00391 }
00392 else {
00393 if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) {
00394 throw new ZipException("Invalid password");
00395 }
00396 }
00397
00398 if (csize >= ZipConstants.CRYPTO_HEADER_SIZE) {
00399 csize -= ZipConstants.CRYPTO_HEADER_SIZE;
00400 }
00401 }
00402 else {
00403 inputBuffer.CryptoTransform = null;
00404 }
00405
00406 if (method == (int)CompressionMethod.Deflated && inputBuffer.Available > 0) {
00407 inputBuffer.SetInflaterInput(inf);
00408 }
00409
00410 internalReader = new ReaderDelegate(BodyRead);
00411 return BodyRead(destination, offset, count);
00412 }
00413
00414
00423 public override int Read(byte[] destination, int index, int count)
00424 {
00425 return internalReader(destination, index, count);
00426 }
00427
00443 public int BodyRead(byte[] b, int off, int len)
00444 {
00445 if (crc == null) {
00446 throw new InvalidOperationException("Closed.");
00447 }
00448
00449 if (entry == null || len <= 0 ) {
00450 return 0;
00451 }
00452
00453 bool finished = false;
00454
00455 switch (method) {
00456 case (int)CompressionMethod.Deflated:
00457 len = base.Read(b, off, len);
00458 if (len <= 0) {
00459 if (!inf.IsFinished) {
00460 throw new ZipException("Inflater not finished!?");
00461 }
00462 inputBuffer.Available = inf.RemainingInput;
00463
00464 if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
00465 throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
00466 }
00467 inf.Reset();
00468 finished = true;
00469 }
00470 break;
00471
00472 case (int)CompressionMethod.Stored:
00473 if (len > csize && csize >= 0) {
00474 len = (int)csize;
00475 }
00476 len = inputBuffer.ReadClearTextBuffer(b, off, len);
00477 if (len > 0) {
00478 csize -= len;
00479 size -= len;
00480 }
00481
00482 if (csize == 0) {
00483 finished = true;
00484 } else {
00485 if (len < 0) {
00486 throw new ZipException("EOF in stored block");
00487 }
00488 }
00489 break;
00490 }
00491
00492 if (len > 0) {
00493 crc.Update(b, off, len);
00494 }
00495
00496 if (finished) {
00497 StopDecrypting();
00498
00499 if ((flags & 8) != 0) {
00500 ReadDataDescriptor();
00501 }
00502
00503 if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
00504 throw new ZipException("CRC mismatch");
00505 }
00506 crc.Reset();
00507 entry = null;
00508 }
00509 return len;
00510 }
00511
00515 public override void Close()
00516 {
00517 base.Close();
00518 crc = null;
00519 entry = null;
00520 }
00521 }
00522 }