/// <summary>
		/// Test an archive for integrity/validity
		/// </summary>
		/// <param name="testData">Perform low level data Crc check</param>
		/// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param>
		/// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param>
		/// <returns>true if all tests pass, false otherwise</returns>
		public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler)
		{
			TestStatus status = new TestStatus(this);

			if (resultHandler != null)
			{
				resultHandler(status, null);
			}

			HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header;

			bool testing = true;

			try
			{
				int entryIndex = 0;

				while (testing && (entryIndex < Count))
				{
					if (resultHandler != null)
					{
						status.SetEntry(this[entryIndex]);
						status.SetOperation(TestOperation.EntryHeader);
						resultHandler(status, null);
					}

					try
					{
						TestLocalHeader(this[entryIndex], test);
					}
					catch (ZipException ex)
					{
						status.AddError();

						if (resultHandler != null)
						{
							resultHandler(status,
							              string.Format("Exception during test - '{0}'", ex.Message));
						}

						if (strategy == TestStrategy.FindFirstError)
						{
							testing = false;
						}
					}

					if (testing && testData && this[entryIndex].IsFile)
					{
						if (resultHandler != null)
						{
							status.SetOperation(TestOperation.EntryData);
							resultHandler(status, null);
						}

						Stream entryStream = this.GetInputStream(this[entryIndex]);

						Crc32 crc = new Crc32();
						byte[] buffer = new byte[4096];
						long totalBytes = 0;
						int bytesRead;
						while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)
						{
							crc.Update(buffer, 0, bytesRead);

							if (resultHandler != null)
							{
								totalBytes += bytesRead;
								status.SetBytesTested(totalBytes);
								resultHandler(status, null);
							}
						}

						if (this[entryIndex].Crc != crc.Value)
						{
							status.AddError();

							if (resultHandler != null)
							{
								resultHandler(status, "CRC mismatch");
							}

							if (strategy == TestStrategy.FindFirstError)
							{
								testing = false;
							}
						}

						if ((this[entryIndex].Flags & (int) GeneralBitFlags.Descriptor) != 0)
						{
							ZipHelperStream helper = new ZipHelperStream(baseStream_);
							DescriptorData data = new DescriptorData();
							helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data);
							if (this[entryIndex].Crc != data.Crc)
							{
								status.AddError();
							}

							if (this[entryIndex].CompressedSize != data.CompressedSize)
							{
								status.AddError();
							}

							if (this[entryIndex].Size != data.Size)
							{
								status.AddError();
							}
						}
					}

					if (resultHandler != null)
					{
						status.SetOperation(TestOperation.EntryComplete);
						resultHandler(status, null);
					}

					entryIndex += 1;
				}

				if (resultHandler != null)
				{
					status.SetOperation(TestOperation.MiscellaneousTests);
					resultHandler(status, null);
				}

				// TODO: the 'Corrina Johns' test where local headers are missing from
				// the central directory.  They are therefore invisible to many archivers.
			}
			catch (Exception ex)
			{
				status.AddError();

				if (resultHandler != null)
				{
					resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message));
				}
			}

			if (resultHandler != null)
			{
				status.SetOperation(TestOperation.Complete);
				status.SetEntry(null);
				resultHandler(status, null);
			}

			return (status.ErrorCount == 0);
		}
		/// <summary>
		/// Read data descriptor at the end of compressed data.
		/// </summary>
		/// <param name="zip64">if set to <c>true</c> [zip64].</param>
		/// <param name="data">The data to fill in.</param>
		/// <returns>Returns the number of bytes read in the descriptor.</returns>
		public void ReadDataDescriptor(bool zip64, DescriptorData data)
		{
			int intValue = ReadLEInt();

			// In theory this may not be a descriptor according to PKZIP appnote.
			// In practise its always there.
			if (intValue != ZipConstants.DataDescriptorSignature)
			{
				throw new ZipException("Data descriptor signature not found");
			}

			data.Crc = ReadLEInt();

			if (zip64)
			{
				data.CompressedSize = ReadLELong();
				data.Size = ReadLELong();
			}
			else
			{
				data.CompressedSize = ReadLEInt();
				data.Size = ReadLEInt();
			}
		}