Exemplo n.º 1
0
		/// <summary>
		/// Test the 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 test to carry out.</param>
		/// <returns>The offset of the entries data in the file</returns>
		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 size = ReadLEUint();
				long compressedSize = ReadLEUint();
				int storedNameLength = ReadLEUshort();
				int extraDataLength = ReadLEUshort();

				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 != 20) &&
						(extractVersion != 21) &&
						(extractVersion != 25) &&
						(extractVersion != 27) &&
						(extractVersion != 45) &&
						(extractVersion != 46) &&
						(extractVersion != 50) &&
						(extractVersion != 51) &&
						(extractVersion != 61) &&
						(extractVersion != 62)
						) {
						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.Reserved) != 0 ) {
						throw new ZipException("Reserved bit flag cannot bet 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.
					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");
					}

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

					string localName = ZipConstants.ConvertToString(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");
					}

					byte[] data = new byte[extraDataLength];
					StreamUtils.ReadFully(baseStream_, data);
					ZipExtraData ed = new ZipExtraData(data);

					// Extra data / zip64 checks
					if ( ed.Find(1) ) {
						// Zip64 extra data but extract version 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");
						}
					}
				}
					
				int extraLength = storedNameLength + extraDataLength;
				return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
			}
		}
Exemplo n.º 2
0
        /// <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();
                }
            }
            else
            {
                if (
                    ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
                    ((size == uint.MaxValue) ||
                     (compressedSize == uint.MaxValue)))
                {
                    throw new ZipException("Zip64 Extended information required but is missing.");
                }
            }

/* TODO: Testing for handling of windows extra data
 *                      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 = System.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 System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
                                new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
                }
            }
        }
Exemplo n.º 3
0
		/// <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();
				}
			}
			else {
				if ( 
					((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
					( (size == uint.MaxValue) ||
					(compressedSize == uint.MaxValue) )) {
					throw new ZipException("Zip64 Extended information required but is missing.");
				}
			}

/* TODO: Testing for handling of windows extra data
			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 = System.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 System.DateTime ( 1970, 1, 1, 0, 0, 0 ).ToUniversalTime() +
						new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime();
				}
			}
		}