/// <summary>
		/// Test a local header against that provided from the central directory
		/// </summary>
		/// <param name="entry">
		/// The entry to test against
		/// </param>
		/// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
		/// <returns>The offset of the entries data in the file</returns>
		private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
		{
			lock (baseStream_)
			{
				bool testHeader = (tests & HeaderTest.Header) != 0;
				bool testData = (tests & HeaderTest.Extract) != 0;

				baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
				if ((int) ReadLEUint() != ZipConstants.LocalHeaderSignature)
				{
					throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset));
				}

				short extractVersion = (short) ReadLEUshort();
				short localFlags = (short) ReadLEUshort();
				short compressionMethod = (short) ReadLEUshort();
				short fileTime = (short) ReadLEUshort();
				short fileDate = (short) ReadLEUshort();
				uint crcValue = ReadLEUint();
				long compressedSize = ReadLEUint();
				long size = ReadLEUint();
				int storedNameLength = ReadLEUshort();
				int extraDataLength = ReadLEUshort();

				byte[] nameData = new byte[storedNameLength];
				StreamUtils.ReadFully(baseStream_, nameData);

				byte[] extraData = new byte[extraDataLength];
				StreamUtils.ReadFully(baseStream_, extraData);

				ZipExtraData ed = new ZipExtraData(extraData);

				// Extra data / zip64 checks
				if (ed.Find(1))
				{
					// TODO Check for tag values being distinct..  Multiple zip64 tags means what?

					// Zip64 extra data but 'extract version' is too low
					if (extractVersion < ZipConstants.VersionZip64)
					{
						throw new ZipException(
							string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough",
							              extractVersion/10, extractVersion%10));
					}

					// Zip64 extra data but size fields dont indicate its required.
					if (((uint) size != uint.MaxValue) && ((uint) compressedSize != uint.MaxValue))
					{
						throw new ZipException("Entry sizes not correct for Zip64");
					}

					size = ed.ReadLong();
					compressedSize = ed.ReadLong();
				}
				else
				{
					// No zip64 extra data but entry requires it.
					if ((extractVersion >= ZipConstants.VersionZip64) &&
					    (((uint) size == uint.MaxValue) || ((uint) compressedSize == uint.MaxValue)))
					{
						throw new ZipException("Required Zip64 extended information missing");
					}
				}

				if (testData)
				{
					if (entry.IsFile)
					{
						if (!entry.IsCompressionMethodSupported())
						{
							throw new ZipException("Compression method not supported");
						}

						if ((extractVersion > ZipConstants.VersionMadeBy)
						    || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)))
						{
							throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion));
						}

						if ((localFlags & (int) (GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0)
						{
							throw new ZipException("The library does not support the zip version required to extract this entry");
						}
					}
				}

				if (testHeader)
				{
					if ((extractVersion <= 63) && // Ignore later versions as we dont know about them..
					    (extractVersion != 10) &&
					    (extractVersion != 11) &&
					    (extractVersion != 20) &&
					    (extractVersion != 21) &&
					    (extractVersion != 25) &&
					    (extractVersion != 27) &&
					    (extractVersion != 45) &&
					    (extractVersion != 46) &&
					    (extractVersion != 50) &&
					    (extractVersion != 51) &&
					    (extractVersion != 52) &&
					    (extractVersion != 61) &&
					    (extractVersion != 62) &&
					    (extractVersion != 63)
						)
					{
						throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion));
					}

					// Local entry flags dont have reserved bit set on.
					if ((localFlags & (int) (GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0)
					{
						throw new ZipException("Reserved bit flags cannot be set.");
					}

					// Encryption requires extract version >= 20
					if (((localFlags & (int) GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))
					{
						throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
					}

					// Strong encryption requires encryption flag to be set and extract version >= 50.
					if ((localFlags & (int) GeneralBitFlags.StrongEncryption) != 0)
					{
						if ((localFlags & (int) GeneralBitFlags.Encrypted) == 0)
						{
							throw new ZipException("Strong encryption flag set but encryption flag is not set");
						}

						if (extractVersion < 50)
						{
							throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
						}
					}

					// Patched entries require extract version >= 27
					if (((localFlags & (int) GeneralBitFlags.Patched) != 0) && (extractVersion < 27))
					{
						throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
					}

					// Central header flags match local entry flags.
					if (localFlags != entry.Flags)
					{
						throw new ZipException("Central header/local header flags mismatch");
					}

					// Central header compression method matches local entry
					if (entry.CompressionMethod != (CompressionMethod) compressionMethod)
					{
						throw new ZipException("Central header/local header compression method mismatch");
					}

					// Strong encryption and extract version match
					if ((localFlags & (int) GeneralBitFlags.StrongEncryption) != 0)
					{
						if (extractVersion < 62)
						{
							throw new ZipException("Strong encryption flag set but version not high enough");
						}
					}

					if ((localFlags & (int) GeneralBitFlags.HeaderMasked) != 0)
					{
						if ((fileTime != 0) || (fileDate != 0))
						{
							throw new ZipException("Header masked set but date/time values non-zero");
						}
					}

					if ((localFlags & (int) GeneralBitFlags.Descriptor) == 0)
					{
						if (crcValue != (uint) entry.Crc)
						{
							throw new ZipException("Central header/local header crc mismatch");
						}
					}

					// Crc valid for empty entry.
					// This will also apply to streamed entries where size isnt known and the header cant be patched
					if ((size == 0) && (compressedSize == 0))
					{
						if (crcValue != 0)
						{
							throw new ZipException("Invalid CRC for empty entry");
						}
					}

					// TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS strings
					// Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
					if (entry.Name.Length > storedNameLength)
					{
						throw new ZipException("File name length mismatch");
					}

					// Name data has already been read convert it and compare.
					string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);

					// Central directory and local entry name match
					if (localName != entry.Name)
					{
						throw new ZipException("Central header and local header file name mismatch");
					}

					// Directories have zero size.
					if (entry.IsDirectory)
					{
						if ((compressedSize != 0) || (size != 0))
						{
							throw new ZipException("Directory cannot have size");
						}
					}

					if (!ZipNameTransform.IsValidName(localName, true))
					{
						throw new ZipException("Name is invalid");
					}
				}

				// Tests that apply to both data and header.

				// Size can be verified only if it is known in the local header.
				// it will always be known in the central header.
				if ((localFlags & (int) GeneralBitFlags.Descriptor) == 0 ||
				    (size != 0 || compressedSize != 0))
				{
					if (size != entry.Size)
					{
						throw new ZipException(
							string.Format("Size mismatch between central header({0}) and local header({1})",
							              entry.Size, size));
					}

					if (compressedSize != entry.CompressedSize)
					{
						throw new ZipException(
							string.Format("Compressed size mismatch between central header({0}) and local header({1})",
							              entry.CompressedSize, compressedSize));
					}
				}

				int extraLength = storedNameLength + extraDataLength;
				return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
			}
		}
		/// <summary>
		/// Process extra data fields updating the entry based on the contents.
		/// </summary>
		/// <param name="localHeader">True if the extra data fields should be handled
		/// for a local header, rather than for a central header.
		/// </param>
		internal void ProcessExtraData(bool localHeader)
		{
			ZipExtraData extraData = new ZipExtraData(this.extra);

			if (extraData.Find(0x0001))
			{
				if ((versionToExtract & 0xff) < ZipConstants.VersionZip64)
				{
					throw new ZipException("Zip64 Extended information found but version is not valid");
				}

				// The recorded size will change but remember that this is zip64.
				forceZip64_ = true;

				if (extraData.ValueLength < 4)
				{
					throw new ZipException("Extra data extended Zip64 information length is invalid");
				}

				if (localHeader || (size == uint.MaxValue))
				{
					size = (ulong) extraData.ReadLong();
				}

				if (localHeader || (compressedSize == uint.MaxValue))
				{
					compressedSize = (ulong) extraData.ReadLong();
				}

				if (!localHeader && (offset == uint.MaxValue))
				{
					offset = extraData.ReadLong();
				}
			}
			else
			{
				if (
					((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
					((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
					)
				{
					throw new ZipException("Zip64 Extended information required but is missing.");
				}
			}

			if (extraData.Find(10))
			{
				// No room for any tags.
				if (extraData.ValueLength < 8)
				{
					throw new ZipException("NTFS Extra data invalid");
				}

				extraData.ReadInt(); // Reserved

				while (extraData.UnreadCount >= 4)
				{
					int ntfsTag = extraData.ReadShort();
					int ntfsLength = extraData.ReadShort();
					if (ntfsTag == 1)
					{
						if (ntfsLength >= 24)
						{
							long lastModification = extraData.ReadLong();
							long lastAccess = extraData.ReadLong();
							long createTime = extraData.ReadLong();

							DateTime = DateTime.FromFileTime(lastModification);
						}
						break;
					}
					else
					{
						// An unknown NTFS tag so simply skip it.
						extraData.Skip(ntfsLength);
					}
				}
			}
			else if (extraData.Find(0x5455))
			{
				int length = extraData.ValueLength;
				int flags = extraData.ReadByte();

				// Can include other times but these are ignored.  Length of data should
				// actually be 1 + 4 * no of bits in flags.
				if (((flags & 1) != 0) && (length >= 5))
				{
					int iTime = extraData.ReadInt();

					DateTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
					            new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
				}
			}
		}