private void ReadLocator(MarkingBinaryReader reader)
        {
            var size = reader.ReadRarVIntUInt16();
            var type = reader.ReadRarVIntUInt16();

            if (type != 1)
            {
                throw new InvalidFormatException("expected locator record");
            }

            var          flags = reader.ReadRarVIntUInt16();
            const ushort hasQuickOpenOffset = 0x01;
            const ushort hasRecoveryOffset  = 0x02;
            ulong        quickOpenOffset    = 0;

            if ((flags & hasQuickOpenOffset) == hasQuickOpenOffset)
            {
                quickOpenOffset = reader.ReadRarVInt();
            }
            ulong recoveryOffset = 0;

            if ((flags & hasRecoveryOffset) == hasRecoveryOffset)
            {
                recoveryOffset = reader.ReadRarVInt();
            }
        }
 protected override void ReadFinish(MarkingBinaryReader reader)
 {
     if (IsRar5)
     {
         Flags = reader.ReadRarVIntUInt16();
         if (HasFlag(ArchiveFlagsV5.HAS_VOLUME_NUMBER))
         {
             VolumeNumber = (int)reader.ReadRarVIntUInt32();
         }
         // later: we may have a locator record if we need it
         //if (ExtraSize != 0) {
         //    ReadLocator(reader);
         //}
     }
     else
     {
         Flags     = HeaderFlags;
         HighPosAv = reader.ReadInt16();
         PosAv     = reader.ReadInt32();
         if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER))
         {
             EncryptionVersion = reader.ReadByte();
         }
     }
 }
 protected override void ReadFinish(MarkingBinaryReader reader)
 {
     if (IsRar5)
     {
         Flags = reader.ReadRarVIntUInt16();
     }
     else
     {
         Flags = HeaderFlags;
         if (HasFlag(EndArchiveFlagsV4.DATA_CRC))
         {
             ArchiveCrc = reader.ReadInt32();
         }
         if (HasFlag(EndArchiveFlagsV4.VOLUME_NUMBER))
         {
             VolumeNumber = reader.ReadInt16();
         }
     }
 }
Beispiel #4
0
        private void ReadFromReaderV5(MarkingBinaryReader reader)
        {
            Flags = reader.ReadRarVIntUInt16();

            var lvalue = checked ((long)reader.ReadRarVInt());

            // long.MaxValue causes the unpack code to finish when the input stream is exhausted
            UncompressedSize = HasFlag(FileFlagsV5.UNPACKED_SIZE_UNKNOWN) ? long.MaxValue : lvalue;

            FileAttributes = reader.ReadRarVIntUInt32();

            if (HasFlag(FileFlagsV5.HAS_MOD_TIME))
            {
                FileLastModifiedTime = Utility.UnixTimeToDateTime(reader.ReadUInt32());
            }

            if (HasFlag(FileFlagsV5.HAS_CRC32))
            {
                FileCrc = reader.ReadUInt32();
            }

            var compressionInfo = reader.ReadRarVIntUInt16();

            // Lower 6 bits (0x003f mask) contain the version of compression algorithm, resulting in possible 0 - 63 values. Current version is 0.
            // "+ 50" to not mix with old RAR format algorithms. For example,
            // we may need to use the compression algorithm 15 in the future,
            // but it was already used in RAR 1.5 and Unpack needs to distinguish
            // them.
            CompressionAlgorithm = (byte)((compressionInfo & 0x3f) + 50);

            // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files.
            // It can be set only for file headers and is never set for service headers.
            IsSolid = (compressionInfo & 0x40) == 0x40;

            // Bits 8 - 10 (0x0380 mask) define the compression method. Currently only values 0 - 5 are used. 0 means no compression.
            CompressionMethod = (byte)((compressionInfo >> 7) & 0x7);

            // Bits 11 - 14 (0x3c00) define the minimum size of dictionary size required to extract data. Value 0 means 128 KB, 1 - 256 KB, ..., 14 - 2048 MB, 15 - 4096 MB.
            WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf);

            HostOs = reader.ReadRarVIntByte();

            var nameSize = reader.ReadRarVIntUInt16();

            // Variable length field containing Name length bytes in UTF-8 format without trailing zero.
            // For file header this is a name of archived file. Forward slash character is used as the path separator both for Unix and Windows names.
            // Backslashes are treated as a part of name for Unix names and as invalid character for Windows file names. Type of name is defined by Host OS field.
            //
            // TODO: not sure if anything needs to be done to handle the following:
            // If Unix file name contains any high ASCII characters which cannot be correctly converted to Unicode and UTF-8
            // we map such characters to to 0xE080 - 0xE0FF private use Unicode area and insert 0xFFFE Unicode non-character
            // to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting.
            // Concrete position of 0xFFFE is not defined, we need to search the entire string for it. Such mapped names are not
            // portable and can be correctly unpacked only on the same system where they were created.
            //
            // For service header this field contains a name of service header. Now the following names are used:
            // CMT	Archive comment
            // QO	Archive quick open data
            // ACL	NTFS file permissions
            // STM	NTFS alternate data stream
            // RR	Recovery record
            var b = reader.ReadBytes(nameSize);

            FileName = ConvertPathV5(Encoding.UTF8.GetString(b, 0, b.Length));

            // extra size seems to be redudant since we know the total header size
            if (ExtraSize != RemainingHeaderBytes(reader))
            {
                throw new InvalidFormatException("rar5 header size / extra size inconsistency");
            }

            isEncryptedRar5 = false;

            while (RemainingHeaderBytes(reader) > 0)
            {
                var size = reader.ReadRarVIntUInt16();
                int n    = RemainingHeaderBytes(reader);
                var type = reader.ReadRarVIntUInt16();
                switch (type)
                {
                //TODO
                case 1:     // file encryption
                {
                    isEncryptedRar5 = true;

                    //var version = reader.ReadRarVIntByte();
                    //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version);
                }
                break;

                //                    case 2: // file hash
                //                        {
                //
                //                        }
                //                        break;
                case 3:     // file time
                {
                    ushort flags         = reader.ReadRarVIntUInt16();
                    var    isWindowsTime = (flags & 1) == 0;
                    if ((flags & 0x2) == 0x2)
                    {
                        FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime);
                    }
                    if ((flags & 0x4) == 0x4)
                    {
                        FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime);
                    }
                    if ((flags & 0x8) == 0x8)
                    {
                        FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime);
                    }
                }
                break;
//TODO
//                    case 4: // file version
//                        {
//
//                        }
//                        break;
//                    case 5: // file system redirection
//                        {
//
//                        }
//                        break;
//                    case 6: // unix owner
//                        {
//
//                        }
//                        break;
//                    case 7: // service data
//                        {
//
//                        }
//                        break;

                default:
                    // skip unknown record types to allow new record types to be added in the future
                    break;
                }
                // drain any trailing bytes of extra record
                int did   = n - RemainingHeaderBytes(reader);
                int drain = size - did;
                if (drain > 0)
                {
                    reader.ReadBytes(drain);
                }
            }

            if (AdditionalDataSize != 0)
            {
                CompressedSize = AdditionalDataSize;
            }
        }