예제 #1
0
        public HfsEntry(HfsEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            known                  = entry.known;
            name                   = entry.name;
            size                   = entry.size;
            compressedSize         = entry.compressedSize;
            crc                    = entry.crc;
            dosTime                = entry.dosTime;
            method                 = entry.method;
            comment                = entry.comment;
            versionToExtract       = entry.versionToExtract;
            versionMadeBy          = entry.versionMadeBy;
            externalFileAttributes = entry.externalFileAttributes;
            flags                  = entry.flags;

            HfsFileIndex = entry.HfsFileIndex;
            offset       = entry.offset;

            if (entry.extra != null)
            {
                extra = new byte[entry.extra.Length];
                Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
            }
        }
예제 #2
0
        // Write the local file header
        // TODO: HfsHelperStream.WriteLocalHeader is not yet used and needs checking for HfsFile and HfsOuptutStream usage
        void WriteLocalHeader(HfsEntry entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true; // How to get this?

            WriteLEInt(HfsConstants.LocalHeaderSignature);

            WriteLEShort(entry.Version);
            WriteLEShort(entry.Flags);
            WriteLEShort((byte)method);
            WriteLEInt((int)entry.DosTime);

            if (headerInfoAvailable == true)
            {
                WriteLEInt((int)entry.CompressedSize);
                WriteLEInt((int)entry.Size);
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = stream_.Position;
                }
                WriteLEInt(0);  // Crc

                if (patchData != null)
                {
                    patchData.SizePatchOffset = stream_.Position;
                }

                WriteLEInt(0);  // Compressed size
                WriteLEInt(0);  // Uncompressed size
            }

            byte[] name = HfsConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new HfsException("Entry name too long.");
            }

            byte[] extra = new byte[0];

            WriteLEShort(name.Length);
            WriteLEShort(extra.Length);

            if (name.Length > 0)
            {
                stream_.Write(name, 0, name.Length);
            }

            if (extra.Length > 0)
            {
                stream_.Write(extra, 0, extra.Length);
            }
        }
예제 #3
0
        /// <summary>
        /// Creates a copy of this Hfs entry.
        /// </summary>
        /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>
        public object Clone()
        {
            HfsEntry result = (HfsEntry)this.MemberwiseClone();

            // Ensure extra data is unique if it exists.
            if (extra != null)
            {
                result.extra = new byte[extra.Length];
                Array.Copy(extra, 0, result.extra, 0, extra.Length);
            }

            return(result);
        }
예제 #4
0
 public HfsUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new HfsEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     dataSource_ = dataSource;
 }
예제 #5
0
 public HfsUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new HfsEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     filename_ = fileName;
 }
예제 #6
0
        /// <summary>
        /// Make a new <see cref="HfsEntry"></see> for a directory.
        /// </summary>
        /// <param name="directoryName">The raw untransformed name for the new directory</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="HfsEntry"></see> representing a directory.</returns>
        public HfsEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
        {
            HfsEntry result = new HfsEntry(nameTransform_.TransformDirectory(directoryName));

            result.Size = 0;

            int externalAttributes = 0;

            DirectoryInfo di = null;

            if (useFileSystem)
            {
                di = new DirectoryInfo(directoryName);
            }


            if ((di != null) && di.Exists)
            {
                switch (timeSetting_)
                {
                case TimeSetting.CreateTime:
                    result.DateTime = di.CreationTime;
                    break;

                case TimeSetting.CreateTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = di.CreationTime.ToUniversalTime();
#else
                    result.DateTime = di.CreationTimeUtc;
#endif
                    break;

                case TimeSetting.LastAccessTime:
                    result.DateTime = di.LastAccessTime;
                    break;

                case TimeSetting.LastAccessTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = di.LastAccessTime.ToUniversalTime();
#else
                    result.DateTime = di.LastAccessTimeUtc;
#endif
                    break;

                case TimeSetting.LastWriteTime:
                    result.DateTime = di.LastWriteTime;
                    break;

                case TimeSetting.LastWriteTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = di.LastWriteTime.ToUniversalTime();
#else
                    result.DateTime = di.LastWriteTimeUtc;
#endif
                    break;

                case TimeSetting.Fixed:
                    result.DateTime = fixedDateTime_;
                    break;

                default:
                    throw new HfsException("Unhandled time setting in MakeDirectoryEntry");
                }

                externalAttributes = ((int)di.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            // Always set directory attribute on.
            externalAttributes           |= (setAttributes_ | 16);
            result.ExternalFileAttributes = externalAttributes;

            return(result);
        }
        // Write the local file header
        // TODO: HfsHelperStream.WriteLocalHeader is not yet used and needs checking for HfsFile and HfsOuptutStream usage
        void WriteLocalHeader(HfsEntry entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true; // How to get this?

            WriteLEInt(HfsConstants.LocalHeaderSignature);

            WriteLEShort(entry.Version);
            WriteLEShort(entry.Flags);
            WriteLEShort((byte)method);
            WriteLEInt((int)entry.DosTime);

            if (headerInfoAvailable == true)
            {
                WriteLEInt((int)entry.CompressedSize);
                WriteLEInt((int)entry.Size);
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = stream_.Position;
                }
                WriteLEInt(0);	// Crc

                if (patchData != null)
                {
                    patchData.SizePatchOffset = stream_.Position;
                }

                WriteLEInt(0);	// Compressed size
                WriteLEInt(0);	// Uncompressed size
            }

            byte[] name = HfsConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new HfsException("Entry name too long.");
            }

            byte[] extra = new byte[0];

            WriteLEShort(name.Length);
            WriteLEShort(extra.Length);

            if (name.Length > 0)
            {
                stream_.Write(name, 0, name.Length);
            }

            if (extra.Length > 0)
            {
                stream_.Write(extra, 0, extra.Length);
            }
        }
        /// <summary>
        /// Make a new <see cref="HfsEntry"></see> for a directory.
        /// </summary>
        /// <param name="directoryName">The raw untransformed name for the new directory</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="HfsEntry"></see> representing a directory.</returns>
        public HfsEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
        {
            HfsEntry result = new HfsEntry(nameTransform_.TransformDirectory(directoryName));
            result.Size = 0;

            int externalAttributes = 0;

            DirectoryInfo di = null;

            if (useFileSystem)
            {
                di = new DirectoryInfo(directoryName);
            }

            if ((di != null) && di.Exists)
            {
                switch (timeSetting_)
                {
                    case TimeSetting.CreateTime:
                        result.DateTime = di.CreationTime;
                        break;

                    case TimeSetting.CreateTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = di.CreationTime.ToUniversalTime();
            #else
                        result.DateTime = di.CreationTimeUtc;
            #endif
                        break;

                    case TimeSetting.LastAccessTime:
                        result.DateTime = di.LastAccessTime;
                        break;

                    case TimeSetting.LastAccessTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = di.LastAccessTime.ToUniversalTime();
            #else
                        result.DateTime = di.LastAccessTimeUtc;
            #endif
                        break;

                    case TimeSetting.LastWriteTime:
                        result.DateTime = di.LastWriteTime;
                        break;

                    case TimeSetting.LastWriteTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = di.LastWriteTime.ToUniversalTime();
            #else
                        result.DateTime = di.LastWriteTimeUtc;
            #endif
                        break;

                    case TimeSetting.Fixed:
                        result.DateTime = fixedDateTime_;
                        break;

                    default:
                        throw new HfsException("Unhandled time setting in MakeDirectoryEntry");
                }

                externalAttributes = ((int)di.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            // Always set directory attribute on.
            externalAttributes |= (setAttributes_ | 16);
            result.ExternalFileAttributes = externalAttributes;

            return result;
        }
예제 #9
0
 internal void SetEntry(HfsEntry entry)
 {
     entry_ = entry;
     entryValid_ = true;
     bytesTested_ = 0;
 }
예제 #10
0
 public HfsUpdate(UpdateCommand command, HfsEntry entry)
 {
     command_ = command;
     entry_ = (HfsEntry)entry.Clone();
 }
예제 #11
0
 /// <summary>
 /// Locate the data for a given entry.
 /// </summary>
 /// <returns>
 /// The start offset of the data.
 /// </returns>
 /// <exception cref="System.IO.EndOfStreamException">
 /// The stream ends prematurely
 /// </exception>
 /// <exception cref="ICSharpCode.SharpZipLib.Hfs.HfsException">
 /// The local header signature is invalid, the entry and central header file name lengths are different
 /// or the local and entry compression methods dont match
 /// </exception>
 long LocateEntry(HfsEntry entry)
 {
     return TestLocalHeader(entry, HeaderTest.Extract);
 }
예제 #12
0
        /// <summary>
        /// Get an output stream for the specified <see cref="HfsEntry"/>
        /// </summary>
        /// <param name="entry">The entry to get an output stream for.</param>
        /// <returns>The output stream obtained for the entry.</returns>
        Stream GetOutputStream(HfsEntry entry)
        {
            Stream result = baseStream_;
            long start = result.Position;

            switch (entry.CompressionMethod)
            {
                case CompressionMethod.Stored:
                    {
                        Stream base_result = result;

                        if (entry.Name.Substring(entry.Name.Length - 5) == ".comp")
                        {
                            start += 8;
                        }

                        result = new HFSXorStream(result, start, HfsXorCipher.XorTruths, false);

                        // post process instead
                        //if (obfuscationkey_ > 0)
                        //{
                        //   result = new HFSXorStream(result, start, bytekey_, true);
                        //}

                        if (entry.Name.Substring(entry.Name.Length - 5) == ".comp")
                        {
                            using (MemoryStream ms = new MemoryStream())
                            using (BinaryWriter writer = new BinaryWriter(ms))
                            {
                                writer.Write((UInt32)HfsConstants.CompSignature);
                                writer.Write((UInt32)entry.Size);

                                ms.Seek(0, SeekOrigin.Begin);

                                byte[] buff = new byte[ms.Length];
                                ms.Read(buff, 0, buff.Length);

                                HfsXorCipher.XorBlockWithKey(buff, HfsXorCipher.XorTruths, (int)start - 8);

                                //if (obfuscationkey_ > 0)
                                //{
                                //    HfsXorCipher.XorBlockWithKey(buff, bytekey_, (int)start - 8);
                                //}

                                start += buff.Length;

                                base_result.Write(buff, 0, buff.Length);
                            }

                            DeflaterOutputStream dos = new DeflaterOutputStream(result, new Deflater(9, false));
                            result = dos;
                            dos.IsStreamOwner = false;
                        }

                    }
                    break;

                default:
                    throw new HfsException("Unknown compression method " + entry.CompressionMethod);
            }
            return result;
        }
예제 #13
0
        int FindExistingUpdate(HfsEntry entry)
        {
            int result = -1;
            string convertedName = GetTransformedFileName(entry.Name);

            if (updateIndex_.ContainsKey(convertedName))
            {
                result = (int)updateIndex_[convertedName];
            }
            /*
                        // This is slow like the coming of the next ice age but takes less storage and may be useful
                        // for CF?
                        for (int index = 0; index < updates_.Count; ++index)
                        {
                            HfsUpdate zu = ( HfsUpdate )updates_[index];
                            if ( (zu.Entry.HfsFileIndex == entry.HfsFileIndex) &&
                                (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
                                result = index;
                                break;
                            }
                        }
             */
            return result;
        }
예제 #14
0
        /// <summary>
        /// Gets an input stream for reading the given Hfs entry data in an uncompressed form.
        /// Normally the <see cref="HfsEntry"/> should be an entry returned by GetEntry().
        /// </summary>
        /// <param name="entry">The <see cref="HfsEntry"/> to obtain a data <see cref="Stream"/> for</param>
        /// <returns>An input <see cref="Stream"/> containing data for this <see cref="HfsEntry"/></returns>
        /// <exception cref="ObjectDisposedException">
        /// The HfsFile has already been closed
        /// </exception>
        /// <exception cref="ICSharpCode.SharpZipLib.Hfs.HfsException">
        /// The compression method for the entry is unknown
        /// </exception>
        /// <exception cref="IndexOutOfRangeException">
        /// The entry is not found in the HfsFile
        /// </exception>
        public Stream GetInputStream(HfsEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            if (isDisposed_)
            {
                throw new ObjectDisposedException("HfsFile");
            }

            long index = entry.HfsFileIndex;
            if ((index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name))
            {
                index = FindEntry(entry.Name, true);
                if (index < 0)
                {
                    throw new HfsException("Entry cannot be found");
                }
            }
            return GetInputStream(index);
        }
예제 #15
0
        /// <summary>
        /// Delete a <see cref="HfsEntry"/> from the archive.
        /// </summary>
        /// <param name="entry">The entry to delete.</param>
        public void Delete(HfsEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            CheckUpdating();

            int index = FindExistingUpdate(entry);
            if (index >= 0)
            {
                contentsEdited_ = true;
                updates_[index] = null;
                updateCount_ -= 1;
            }
            else
            {
                throw new HfsException("Cannot find entry to delete");
            }
        }
예제 #16
0
        /// <summary>
        /// Add a <see cref="HfsEntry"/> that contains no data.
        /// </summary>
        /// <param name="entry">The entry to add.</param>
        /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
        public void Add(HfsEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            CheckUpdating();

            if ((entry.Size != 0) || (entry.CompressedSize != 0))
            {
                throw new HfsException("Entry cannot have any data");
            }

            AddUpdate(new HfsUpdate(UpdateCommand.Add, entry));
        }
예제 #17
0
        public HfsEntry(HfsEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            known = entry.known;
            name = entry.name;
            size = entry.size;
            compressedSize = entry.compressedSize;
            crc = entry.crc;
            dosTime = entry.dosTime;
            method = entry.method;
            comment = entry.comment;
            versionToExtract = entry.versionToExtract;
            versionMadeBy = entry.versionMadeBy;
            externalFileAttributes = entry.externalFileAttributes;
            flags = entry.flags;

            HfsFileIndex = entry.HfsFileIndex;
            offset = entry.offset;

            if (entry.extra != null)
            {
                extra = new byte[entry.extra.Length];
                Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
            }
        }
예제 #18
0
 public HfsUpdate(IStaticDataSource dataSource, HfsEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     dataSource_ = dataSource;
 }
예제 #19
0
 public HfsUpdate(HfsEntry original, HfsEntry updated)
 {
     throw new HfsException("Modify not currently supported");
     /*
         command_ = UpdateCommand.Modify;
         entry_ = ( HfsEntry )original.Clone();
         outEntry_ = ( HfsEntry )updated.Clone();
     */
 }
예제 #20
0
        /// <summary>
        /// Search for and read the central directory of a Hfs file filling the entries array.
        /// </summary>
        /// <exception cref="System.IO.IOException">
        /// An i/o error occurs.
        /// </exception>
        /// <exception cref="ICSharpCode.SharpZipLib.Hfs.HfsException">
        /// The central directory is malformed or cannot be found
        /// </exception>
        void ReadEntries()
        {
            // Search for the End Of Central Directory.  When a Hfs comment is
            // present the directory will start earlier
            //
            // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
            // This should be compatible with both SFX and Hfs files but has only been tested for Hfs files
            // If a SFX file has the Hfs data attached as a resource and there are other resources occuring later then
            // this could be invalid.
            // Could also speed this up by reading memory in larger blocks.

            if (baseStream_.CanSeek == false)
            {
                throw new HfsException("HfsFile stream must be seekable");
            }

            long locatedEndOfCentralDir = LocateBlockWithSignature(HfsConstants.EndOfCentralDirectorySignature,
                baseStream_.Length, HfsConstants.EndOfCentralRecordBaseSize, 0xffff);

            if (locatedEndOfCentralDir < 0)
            {
                throw new HfsException("Cannot find central directory");
            }

            // Read end of central directory record
            ushort thisDiskNumber = ReadLEUshort();
            ushort startCentralDirDisk = ReadLEUshort();
            ulong entriesForThisDisk = ReadLEUshort();
            ulong entriesForWholeCentralDir = ReadLEUshort();
            ulong centralDirSize = ReadLEUint();
            long offsetOfCentralDir = ReadLEUint();
            uint commentSize = ReadLEUshort();

            if (baseStream_.Position == (baseStream_.Length - 4))
            {
                obfuscationkey_ = (UInt32)centralDirSize * (UInt32)offsetOfCentralDir;
                bytekey_ = BitConverter.GetBytes(obfuscationkey_);
            }

            if (commentSize > 0)
            {
                byte[] comment = new byte[commentSize];

                StreamUtils.ReadFully(baseStream_, comment);
                comment_ = HfsConstants.ConvertToString(comment);
            }
            else
            {
                comment_ = string.Empty;
            }

            bool isHfs64 = false;

            entries_ = new HfsEntry[entriesForThisDisk];

            // SFX/embedded support, find the offset of the first entry vis the start of the stream
            // This applies to Hfs files that are appended to the end of an SFX stub.
            // Or are appended as a resource to an executable.
            // Hfs files created by some archivers have the offsets altered to reflect the true offsets
            // and so dont require any adjustment here...
            // TODO: Difficulty with Hfs64 and SFX offset handling needs resolution - maths?
            if (!isHfs64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)))
            {
                offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
                if (offsetOfFirstEntry <= 0)
                {
                    throw new HfsException("Invalid embedded Hfs archive");
                }
            }

            baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);

            for (ulong i = 0; i < entriesForThisDisk; i++)
            {
                if (ReadLEUint() != HfsConstants.CentralHeaderSignature)
                {
                    throw new HfsException("Wrong Central Directory signature");
                }

                int versionMadeBy = ReadLEUshort();
                int versionToExtract = ReadLEUshort();
                int bitFlags = ReadLEUshort();
                int method = ReadLEUshort();
                uint dostime = ReadLEUint();
                uint crc = ReadLEUint();
                long csize = (long)ReadLEUint();
                long size = (long)ReadLEUint();
                int nameLen = ReadLEUshort();
                int extraLen = ReadLEUshort();
                int commentLen = ReadLEUshort();

                int diskStartNo = ReadLEUshort();  // Not currently used
                int internalAttributes = ReadLEUshort();  // Not currently used

                uint externalAttributes = ReadLEUint();
                long offset = ReadLEUint();

                byte[] buffer = new byte[Math.Max(nameLen, commentLen)];

                long position = baseStream_.Position;
                StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
                string name = HfsConstants.ConvertToStringObfs(buffer, nameLen, (int)position);

                HfsEntry entry = new HfsEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
                entry.Crc = crc & 0xffffffffL;
                entry.Size = size & 0xffffffffL;
                entry.CompressedSize = csize & 0xffffffffL;
                entry.Flags = bitFlags;
                entry.DosTime = (uint)dostime;
                entry.HfsFileIndex = (long)i;
                entry.Offset = offset;
                entry.ExternalFileAttributes = (int)externalAttributes;

                if (extraLen > 0)
                {
                    byte[] extra = new byte[extraLen];
                    StreamUtils.ReadFully(baseStream_, extra);
                    entry.ExtraData = extra;
                }

                if (commentLen > 0)
                {
                    StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
                    entry.Comment = HfsConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
                }

                entries_[i] = entry;
            }
        }
예제 #21
0
 /// <summary>
 /// Copy an existing entry.
 /// </summary>
 /// <param name="entry">The existing entry to copy.</param>
 public HfsUpdate(HfsEntry entry)
     : this(UpdateCommand.Copy, entry)
 {
     // Do nothing.
 }
예제 #22
0
        /// <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>
        long TestLocalHeader(HfsEntry 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() != HfsConstants.LocalHeaderSignature)
                {
                    throw new HfsException(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();

                long base_buffpos = baseStream_.Position;

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

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

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

                        if ((extractVersion > HfsConstants.VersionMadeBy))
                        {
                            throw new HfsException(string.Format("Version required to extract this entry not supported ({0})", extractVersion));
                        }

                    }
                }

                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 HfsException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion));
                    }

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

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

                    if (entry.Version != extractVersion)
                    {
                        throw new HfsException("Extract version 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 HfsException("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 HfsEntry probably
                    if (entry.Name.Length > storedNameLength)
                    {
                        throw new HfsException("File name length mismatch");
                    }

                    // Name data has already been read convert it and compare.
                    string localName = HfsConstants.ConvertToStringObfs(nameData, storedNameLength, (int)base_buffpos);

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

                    // Directories have zero actual size but can have compressed size
                    if (entry.IsDirectory)
                    {
                        if (size > 0)
                        {
                            throw new HfsException("Directory cannot have size");
                        }
                    }

                    if (!HfsNameTransform.IsValidName(localName, true))
                    {
                        throw new HfsException("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 (((size > 0) || (compressedSize > 0)))
                {

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

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

                int extraLength = storedNameLength + extraDataLength;
                return offsetOfFirstEntry + entry.Offset + HfsConstants.LocalHeaderBaseSize + extraLength;
            }
        }
예제 #23
0
        /// <summary>
        /// Get a <see cref="Stream"/> providing data for an entry.
        /// </summary>
        /// <param name="entry">The entry to provide data for.</param>
        /// <param name="name">The file name for data if known.</param>
        /// <returns>Returns a stream providing data; or null if not available</returns>
        public Stream GetSource(HfsEntry entry, string name)
        {
            Stream result = null;

            if (name != null)
            {
                result = File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
            }

            return result;
        }
예제 #24
0
        int WriteCentralDirectoryHeader(HfsEntry entry)
        {
            if (entry.CompressedSize < 0)
            {
                throw new HfsException("Attempt to write central directory entry with unknown csize");
            }

            if (entry.Size < 0)
            {
                throw new HfsException("Attempt to write central directory entry with unknown size");
            }

            if (entry.Crc < 0)
            {
                throw new HfsException("Attempt to write central directory entry with unknown crc");
            }

            // Write the central file header
            WriteLEInt(HfsConstants.CentralHeaderSignature);

            // Version made by
            WriteLEShort(HfsConstants.VersionMadeBy);

            // Version required to extract
            WriteLEShort(entry.Version);

            WriteLEShort(entry.Flags);

            unchecked
            {
                WriteLEShort((byte)entry.CompressionMethod);
                WriteLEInt((int)entry.DosTime);
                WriteLEInt((int)entry.Crc);
            }

            WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
            WriteLEInt((int)entry.Size);

            byte[] name = HfsConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new HfsException("Entry name is too long.");
            }

            WriteLEShort(name.Length);

            byte[] centralExtraData = new byte[0];

            WriteLEShort(centralExtraData.Length);
            WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);

            WriteLEShort(0);	// disk number
            WriteLEShort(0);	// internal file attributes

            // External file attributes...
            if (entry.ExternalFileAttributes != -1)
            {
                WriteLEInt(entry.ExternalFileAttributes);
            }
            else
            {
                if (entry.IsDirectory)
                {
                    WriteLEUint(16);
                }
                else
                {
                    WriteLEUint(0);
                }
            }

            if (entry.Offset >= 0xffffffff)
            {
                WriteLEUint(0xffffffff);
            }
            else
            {
                WriteLEUint((uint)(int)entry.Offset);
            }

            HfsXorCipher.XorBlockWithKey(name, HfsXorCipher.XorTruths, (int)baseStream_.Position);

            if (name.Length > 0)
            {
                baseStream_.Write(name, 0, name.Length);
            }

            if (centralExtraData.Length > 0)
            {
                baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
            }

            byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];

            if (rawComment.Length > 0)
            {
                baseStream_.Write(rawComment, 0, rawComment.Length);
            }

            return HfsConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
        }
예제 #25
0
        /// <summary>
        /// Make a new <see cref="HfsEntry"/> from a name.
        /// </summary>
        /// <param name="fileName">The name of the file to create a new entry for.</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="HfsEntry"/> based on the <paramref name="fileName"/>.</returns>
        public HfsEntry MakeFileEntry(string fileName, bool useFileSystem)
        {
            HfsEntry result = new HfsEntry(nameTransform_.TransformFile(fileName));

            int externalAttributes = 0;
            bool useAttributes = (setAttributes_ != 0);

            FileInfo fi = null;
            if (useFileSystem)
            {
                fi = new FileInfo(fileName);
            }

            if ((fi != null) && fi.Exists)
            {
                switch (timeSetting_)
                {
                    case TimeSetting.CreateTime:
                        result.DateTime = fi.CreationTime;
                        break;

                    case TimeSetting.CreateTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = fi.CreationTime.ToUniversalTime();
            #else
                        result.DateTime = fi.CreationTimeUtc;
            #endif
                        break;

                    case TimeSetting.LastAccessTime:
                        result.DateTime = fi.LastAccessTime;
                        break;

                    case TimeSetting.LastAccessTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = fi.LastAccessTime.ToUniversalTime();
            #else
                        result.DateTime = fi.LastAccessTimeUtc;
            #endif
                        break;

                    case TimeSetting.LastWriteTime:
                        result.DateTime = fi.LastWriteTime;
                        break;

                    case TimeSetting.LastWriteTimeUtc:
            #if NETCF_1_0 || NETCF_2_0
                        result.DateTime = fi.LastWriteTime.ToUniversalTime();
            #else
                        result.DateTime = fi.LastWriteTimeUtc;
            #endif
                        break;

                    case TimeSetting.Fixed:
                        result.DateTime = fixedDateTime_;
                        break;

                    default:
                        throw new HfsException("Unhandled time setting in MakeFileEntry");
                }

                result.Size = fi.Length;

                useAttributes = true;
                externalAttributes = ((int)fi.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            if (useAttributes)
            {
                externalAttributes |= setAttributes_;
                result.ExternalFileAttributes = externalAttributes;
            }

            return result;
        }
예제 #26
0
 public HfsUpdate(string fileName, HfsEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     filename_ = fileName;
 }
예제 #27
0
 public HfsEntryEnumerator(HfsEntry[] entries)
 {
     array = entries;
 }
예제 #28
0
        /// <summary>
        /// Make a new <see cref="HfsEntry"/> from a name.
        /// </summary>
        /// <param name="fileName">The name of the file to create a new entry for.</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="HfsEntry"/> based on the <paramref name="fileName"/>.</returns>
        public HfsEntry MakeFileEntry(string fileName, bool useFileSystem)
        {
            HfsEntry result = new HfsEntry(nameTransform_.TransformFile(fileName));

            int  externalAttributes = 0;
            bool useAttributes      = (setAttributes_ != 0);

            FileInfo fi = null;

            if (useFileSystem)
            {
                fi = new FileInfo(fileName);
            }

            if ((fi != null) && fi.Exists)
            {
                switch (timeSetting_)
                {
                case TimeSetting.CreateTime:
                    result.DateTime = fi.CreationTime;
                    break;

                case TimeSetting.CreateTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = fi.CreationTime.ToUniversalTime();
#else
                    result.DateTime = fi.CreationTimeUtc;
#endif
                    break;

                case TimeSetting.LastAccessTime:
                    result.DateTime = fi.LastAccessTime;
                    break;

                case TimeSetting.LastAccessTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = fi.LastAccessTime.ToUniversalTime();
#else
                    result.DateTime = fi.LastAccessTimeUtc;
#endif
                    break;

                case TimeSetting.LastWriteTime:
                    result.DateTime = fi.LastWriteTime;
                    break;

                case TimeSetting.LastWriteTimeUtc:
#if NETCF_1_0 || NETCF_2_0
                    result.DateTime = fi.LastWriteTime.ToUniversalTime();
#else
                    result.DateTime = fi.LastWriteTimeUtc;
#endif
                    break;

                case TimeSetting.Fixed:
                    result.DateTime = fixedDateTime_;
                    break;

                default:
                    throw new HfsException("Unhandled time setting in MakeFileEntry");
                }

                result.Size = fi.Length;

                useAttributes      = true;
                externalAttributes = ((int)fi.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            if (useAttributes)
            {
                externalAttributes           |= setAttributes_;
                result.ExternalFileAttributes = externalAttributes;
            }

            return(result);
        }