Пример #1
0
        void ModifyEntry(HfsFile workFile, HfsUpdate update)
        {
            workFile.WriteLocalEntryHeader(update);
            long dataStart = workFile.baseStream_.Position;

            // TODO: This is slow if the changes don't effect the data!!
            if (update.Entry.IsFile && (update.Filename != null))
            {
                using (Stream output = workFile.GetOutputStream(update.OutEntry))
                {
                    using (Stream source = this.GetInputStream(update.Entry))
                    {
                        CopyBytes(update, output, source, source.Length, true);
                    }
                }
            }

            long dataEnd = workFile.baseStream_.Position;
            update.Entry.CompressedSize = dataEnd - dataStart;
        }
Пример #2
0
        void WriteLocalEntryHeader(HfsUpdate update)
        {
            HfsEntry entry = update.OutEntry;

            // TODO: Local offset will require adjusting for multi-disk Hfs files.
            entry.Offset = baseStream_.Position;

            // TODO: Need to clear any entry flags that dont make sense or throw an exception here.
            if (update.Command != UpdateCommand.Copy)
            {

            }

            // Write the local file header
            WriteLEInt(HfsConstants.LocalHeaderSignature);

            WriteLEShort(entry.Version);
            WriteLEShort(entry.Flags);

            WriteLEShort((byte)entry.CompressionMethod);
            WriteLEInt((int)entry.DosTime);

            if (!entry.HasCrc)
            {
                // Note patch address for updating CRC later.
                update.CrcPatchOffset = baseStream_.Position;
                WriteLEInt((int)0);
            }
            else
            {
                WriteLEInt(unchecked((int)entry.Crc));
            }

            if ((entry.CompressedSize < 0) || (entry.Size < 0))
            {
                update.SizePatchOffset = baseStream_.Position;
            }

            WriteLEInt((int)entry.CompressedSize);
            WriteLEInt((int)entry.Size);

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

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

            entry.ExtraData = new byte[0];

            WriteLEShort(name.Length);
            WriteLEShort(entry.ExtraData.Length);

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

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

            if (entry.ExtraData.Length > 0)
            {
                baseStream_.Write(entry.ExtraData, 0, entry.ExtraData.Length);
            }
        }
Пример #3
0
        void CopyEntryDirect(HfsFile workFile, HfsUpdate update, ref long destinationPosition)
        {
            bool skipOver = false;
            if (update.Entry.Offset == destinationPosition)
            {
                skipOver = true;
            }

            if (!skipOver)
            {
                baseStream_.Position = destinationPosition;
                workFile.WriteLocalEntryHeader(update);
                destinationPosition = baseStream_.Position;
            }

            long sourcePosition = 0;

            const int NameLengthOffset = 26;

            // TODO: Add base for SFX friendly handling
            long entryDataOffset = update.Entry.Offset + NameLengthOffset;

            baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);

            // Clumsy way of handling retrieving the original name and extra data length for now.
            // TODO: Stop re-reading name and data length in CopyEntryDirect.
            uint nameLength = ReadLEUshort();
            uint extraLength = ReadLEUshort();

            sourcePosition = baseStream_.Position + nameLength + extraLength;

            if (skipOver)
            {
                if (update.OffsetBasedSize != -1)
                    destinationPosition += update.OffsetBasedSize;
                else
                    // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) archives.
                    // WinHfs produces a warning on these entries:
                    // "caution: value of lrec.csize (compressed size) changed from ..."
                    destinationPosition +=
                        (sourcePosition - entryDataOffset) + NameLengthOffset +	// Header size
                        update.Entry.CompressedSize + GetDescriptorSize(update);
            }
            else
            {
                if (update.Entry.CompressedSize > 0)
                {
                    CopyEntryDataDirect(update, baseStream_, false, ref destinationPosition, ref sourcePosition);
                }
                CopyDescriptorBytesDirect(update, baseStream_, ref destinationPosition, sourcePosition);
            }
        }
Пример #4
0
 /// <summary>
 /// Get the size of the source descriptor for a <see cref="HfsUpdate"/>.
 /// </summary>
 /// <param name="update">The update to get the size for.</param>
 /// <returns>The descriptor size, zero if there isnt one.</returns>
 int GetDescriptorSize(HfsUpdate update)
 {
     int result = 0;
     return result;
 }
Пример #5
0
        void CopyEntry(HfsFile workFile, HfsUpdate update)
        {
            workFile.WriteLocalEntryHeader(update);

            if (update.Entry.CompressedSize > 0)
            {
                const int NameLengthOffset = 26;

                long entryDataOffset = update.Entry.Offset + NameLengthOffset;

                // TODO: This wont work for SFX files!
                baseStream_.Seek(entryDataOffset, SeekOrigin.Begin);

                uint nameLength = ReadLEUshort();
                uint extraLength = ReadLEUshort();

                baseStream_.Seek(nameLength + extraLength, SeekOrigin.Current);

                CopyBytes(update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false);
            }
            CopyDescriptorBytes(update, workFile.baseStream_, baseStream_);
        }
Пример #6
0
        void CopyEntryDataDirect(HfsUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sourcePosition)
        {
            long bytesToCopy = update.Entry.CompressedSize;

            // NOTE: Compressed size is updated elsewhere.
            Crc32 crc = new Crc32();
            byte[] buffer = GetBuffer();

            long targetBytes = bytesToCopy;
            long totalBytesRead = 0;

            int bytesRead;
            do
            {
                int readSize = buffer.Length;

                if (bytesToCopy < readSize)
                {
                    readSize = (int)bytesToCopy;
                }

                stream.Position = sourcePosition;
                bytesRead = stream.Read(buffer, 0, readSize);
                if (bytesRead > 0)
                {
                    if (updateCrc)
                    {
                        crc.Update(buffer, 0, bytesRead);
                    }
                    stream.Position = destinationPosition;
                    stream.Write(buffer, 0, bytesRead);

                    destinationPosition += bytesRead;
                    sourcePosition += bytesRead;
                    bytesToCopy -= bytesRead;
                    totalBytesRead += bytesRead;
                }
            }
            while ((bytesRead > 0) && (bytesToCopy > 0));

            if (totalBytesRead != targetBytes)
            {
                throw new HfsException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
            }

            if (updateCrc)
            {
                update.OutEntry.Crc = crc.Value;
            }
        }
Пример #7
0
        void CopyDescriptorBytesDirect(HfsUpdate update, Stream stream, ref long destinationPosition, long sourcePosition)
        {
            int bytesToCopy = GetDescriptorSize(update);

            while (bytesToCopy > 0)
            {
                int readSize = (int)bytesToCopy;
                byte[] buffer = GetBuffer();

                stream.Position = sourcePosition;
                int bytesRead = stream.Read(buffer, 0, readSize);
                if (bytesRead > 0)
                {
                    stream.Position = destinationPosition;
                    stream.Write(buffer, 0, bytesRead);
                    bytesToCopy -= bytesRead;
                    destinationPosition += bytesRead;
                    sourcePosition += bytesRead;
                }
                else
                {
                    throw new HfsException("Unxpected end of stream");
                }
            }
        }
Пример #8
0
        void CopyDescriptorBytes(HfsUpdate update, Stream dest, Stream source)
        {
            int bytesToCopy = GetDescriptorSize(update);

            if (bytesToCopy > 0)
            {
                byte[] buffer = GetBuffer();

                while (bytesToCopy > 0)
                {
                    int readSize = Math.Min(buffer.Length, bytesToCopy);

                    int bytesRead = source.Read(buffer, 0, readSize);
                    if (bytesRead > 0)
                    {
                        dest.Write(buffer, 0, bytesRead);
                        bytesToCopy -= bytesRead;
                    }
                    else
                    {
                        throw new HfsException("Unxpected end of stream");
                    }
                }
            }
        }
Пример #9
0
        void CopyBytes(HfsUpdate update, Stream destination, Stream source,
            long bytesToCopy, bool updateCrc)
        {
            if (destination == source)
            {
                throw new InvalidOperationException("Destination and source are the same");
            }

            // NOTE: Compressed size is updated elsewhere.
            Crc32 crc = new Crc32();
            byte[] buffer = GetBuffer();

            long targetBytes = bytesToCopy;
            long totalBytesRead = 0;

            int bytesRead;
            do
            {
                int readSize = buffer.Length;

                if (bytesToCopy < readSize)
                {
                    readSize = (int)bytesToCopy;
                }

                bytesRead = source.Read(buffer, 0, readSize);
                if (bytesRead > 0)
                {
                    if (updateCrc)
                    {
                        crc.Update(buffer, 0, bytesRead);
                    }
                    destination.Write(buffer, 0, bytesRead);
                    bytesToCopy -= bytesRead;
                    totalBytesRead += bytesRead;
                }
            }
            while ((bytesRead > 0) && (bytesToCopy > 0));

            if (totalBytesRead != targetBytes)
            {
                throw new HfsException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead));
            }

            if (updateCrc)
            {
                update.OutEntry.Crc = crc.Value;
            }
        }
Пример #10
0
        void AddUpdate(HfsUpdate update)
        {
            contentsEdited_ = true;

            int index = FindExistingUpdate(update.Entry.Name);

            if (index >= 0)
            {
                if (updates_[index] == null)
                {
                    updateCount_ += 1;
                }

                // Direct replacement is faster than delete and add.
                updates_[index] = update;
            }
            else
            {
                index = updates_.Add(update);
                updateCount_ += 1;
                updateIndex_.Add(update.Entry.Name, index);
            }
        }
Пример #11
0
        void AddEntry(HfsFile workFile, HfsUpdate update)
        {
            Stream source = null;

            if (update.Entry.IsFile)
            {
                source = update.GetSource();

                if (source == null)
                {
                    source = updateDataSource_.GetSource(update.Entry, update.Filename);
                }
            }

            if (source != null)
            {
                using (source)
                {
                    long sourceStreamLength = source.Length;
                    if (update.OutEntry.Size < 0)
                    {
                        update.OutEntry.Size = sourceStreamLength;
                    }
                    else
                    {
                        // Check for errant entries.
                        if (update.OutEntry.Size != sourceStreamLength)
                        {
                            throw new HfsException("Entry size/stream size mismatch");
                        }
                    }

                    workFile.WriteLocalEntryHeader(update);

                    long dataStart = workFile.baseStream_.Position;
                    update.OutEntry.DataOffset = dataStart;

                    using (Stream output = workFile.GetOutputStream(update.OutEntry))
                    {
                        CopyBytes(update, output, source, sourceStreamLength, true);
                    }

                    long dataEnd = workFile.baseStream_.Position;

                    update.OutEntry.CompressedSize = update.OutEntry.Size = dataEnd - dataStart;

                }
            }
            else
            {
                workFile.WriteLocalEntryHeader(update);
                update.OutEntry.CompressedSize = 0;
            }
        }