protected override void ReadFinish(MarkingBinaryReader reader) { var cryptVersion = reader.ReadRarVIntUInt32(); if (cryptVersion > CRYPT_VERSION) { //error? return; } var encryptionFlags = reader.ReadRarVIntUInt32(); _usePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); _lg2Count = reader.ReadRarVIntByte(1); //UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); if (_lg2Count > CRYPT5_KDF_LG2_COUNT_MAX) { //error? return; } _salt = reader.ReadBytes(SIZE_SALT50); if (_usePswCheck) { _pswCheck = reader.ReadBytes(SIZE_PSWCHECK); _pswCheckCsm = reader.ReadBytes(SIZE_PSWCHECK_CSUM); } }
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(); } } }
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; } }