Esempio n. 1
0
        public static int ReadFrom(byte[] src, int offset, Encoding enc, out DirectoryRecord record)
        {
            int length = src[offset + 0];

            record = new DirectoryRecord();
            record.ExtendedAttributeRecordLength = src[offset + 1];
            record.LocationOfExtent     = IsoUtilities.ToUInt32FromBoth(src, offset + 2);
            record.DataLength           = IsoUtilities.ToUInt32FromBoth(src, offset + 10);
            record.RecordingDateAndTime = IsoUtilities.ToUTCDateTimeFromDirectoryTime(src, offset + 18);
            record.Flags                = (FileFlags)src[offset + 25];
            record.FileUnitSize         = src[offset + 26];
            record.InterleaveGapSize    = src[offset + 27];
            record.VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 28);
            byte lengthOfFileIdentifier = src[offset + 32];

            record.FileIdentifier = IsoUtilities.ReadChars(src, offset + 33, lengthOfFileIdentifier, enc);

            int padding         = (lengthOfFileIdentifier & 1) == 0 ? 1 : 0;
            int startSystemArea = lengthOfFileIdentifier + padding + 33;
            int lenSystemArea   = length - startSystemArea;

            if (lenSystemArea > 0)
            {
                record.SystemUseData = new byte[lenSystemArea];
                Array.Copy(src, offset + startSystemArea, record.SystemUseData, 0, lenSystemArea);
            }

            return(length);
        }
        public static int ReadFrom(byte[] src, int offset, Encoding enc, out DirectoryRecord record)
        {
            int length = src[offset + 0];

            record = new DirectoryRecord();
            record.ExtendedAttributeRecordLength = src[offset + 1];
            record.LocationOfExtent = IsoUtilities.ToUInt32FromBoth(src, offset + 2);
            record.DataLength = IsoUtilities.ToUInt32FromBoth(src, offset + 10);
            record.RecordingDateAndTime = IsoUtilities.ToUTCDateTimeFromDirectoryTime(src, offset + 18);
            record.Flags = (FileFlags)src[offset + 25];
            record.FileUnitSize = src[offset + 26];
            record.InterleaveGapSize = src[offset + 27];
            record.VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 28);
            byte lengthOfFileIdentifier = src[offset + 32];
            record.FileIdentifier = IsoUtilities.ReadChars(src, offset + 33, lengthOfFileIdentifier, enc);

            int padding = (lengthOfFileIdentifier & 1) == 0 ? 1 : 0;
            int startSystemArea = lengthOfFileIdentifier + padding + 33;
            int lenSystemArea = length - startSystemArea;
            if (lenSystemArea > 0)
            {
                record.SystemUseData = new byte[lenSystemArea];
                Array.Copy(src, offset + startSystemArea, record.SystemUseData, 0, lenSystemArea);
            }

            return length;
        }
        public CommonVolumeDescriptor(byte[] src, int offset, Encoding enc)
            : base(src, offset)
        {
            CharacterEncoding = enc;

            SystemIdentifier               = IsoUtilities.ReadChars(src, offset + 8, 32, CharacterEncoding);
            VolumeIdentifier               = IsoUtilities.ReadChars(src, offset + 40, 32, CharacterEncoding);
            VolumeSpaceSize                = IsoUtilities.ToUInt32FromBoth(src, offset + 80);
            VolumeSetSize                  = IsoUtilities.ToUInt16FromBoth(src, offset + 120);
            VolumeSequenceNumber           = IsoUtilities.ToUInt16FromBoth(src, offset + 124);
            LogicalBlockSize               = IsoUtilities.ToUInt16FromBoth(src, offset + 128);
            PathTableSize                  = IsoUtilities.ToUInt32FromBoth(src, offset + 132);
            TypeLPathTableLocation         = Utilities.ToUInt32LittleEndian(src, offset + 140);
            OptionalTypeLPathTableLocation = Utilities.ToUInt32LittleEndian(src, offset + 144);
            TypeMPathTableLocation         = Utilities.BitSwap(Utilities.ToUInt32LittleEndian(src, offset + 148));
            OptionalTypeMPathTableLocation = Utilities.BitSwap(Utilities.ToUInt32LittleEndian(src, offset + 152));
            DirectoryRecord.ReadFrom(src, offset + 156, CharacterEncoding, out RootDirectory);
            VolumeSetIdentifier         = IsoUtilities.ReadChars(src, offset + 190, 318 - 190, CharacterEncoding);
            PublisherIdentifier         = IsoUtilities.ReadChars(src, offset + 318, 446 - 318, CharacterEncoding);
            DataPreparerIdentifier      = IsoUtilities.ReadChars(src, offset + 446, 574 - 446, CharacterEncoding);
            ApplicationIdentifier       = IsoUtilities.ReadChars(src, offset + 574, 702 - 574, CharacterEncoding);
            CopyrightFileIdentifier     = IsoUtilities.ReadChars(src, offset + 702, 739 - 702, CharacterEncoding);
            AbstractFileIdentifier      = IsoUtilities.ReadChars(src, offset + 739, 776 - 739, CharacterEncoding);
            BibliographicFileIdentifier = IsoUtilities.ReadChars(src, offset + 776, 813 - 776, CharacterEncoding);
            CreationDateAndTime         = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 813);
            ModificationDateAndTime     = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 830);
            ExpirationDateAndTime       = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 847);
            EffectiveDateAndTime        = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 864);
            FileStructureVersion        = src[offset + 881];
        }
Esempio n. 4
0
        private static DirectoryRecord ReadRootSelfRecord(IsoContext context)
        {
            context.DataStream.Position = context.VolumeDescriptor.RootDirectory.LocationOfExtent * context.VolumeDescriptor.LogicalBlockSize;
            byte[] firstSector = Utilities.ReadFully(context.DataStream, context.VolumeDescriptor.LogicalBlockSize);

            DirectoryRecord rootSelfRecord;

            DirectoryRecord.ReadFrom(firstSector, 0, context.VolumeDescriptor.CharacterEncoding, out rootSelfRecord);
            return(rootSelfRecord);
        }
Esempio n. 5
0
        private static void InitializeSusp(IsoContext context, DirectoryRecord rootSelfRecord)
        {
            // Stage 1 - SUSP present?
            List <SuspExtension> extensions = new List <SuspExtension>();

            if (!SuspRecords.DetectSharingProtocol(rootSelfRecord.SystemUseData, 0))
            {
                context.SuspExtensions = new List <SuspExtension>();
                context.SuspDetected   = false;
                return;
            }
            else
            {
                context.SuspDetected = true;
            }

            SuspRecords suspRecords = new SuspRecords(context, rootSelfRecord.SystemUseData, 0);

            // Stage 2 - Init general SUSP params
            SharingProtocolSystemUseEntry spEntry = (SharingProtocolSystemUseEntry)suspRecords.GetEntries(null, "SP")[0];

            context.SuspSkipBytes = spEntry.SystemAreaSkip;

            // Stage 3 - Init extensions
            List <SystemUseEntry> extensionEntries = suspRecords.GetEntries(null, "ER");

            if (extensionEntries != null)
            {
                foreach (ExtensionSystemUseEntry extension in extensionEntries)
                {
                    switch (extension.ExtensionIdentifier)
                    {
                    case "RRIP_1991A":
                    case "IEEE_P1282":
                    case "IEEE_1282":
                        extensions.Add(new RockRidgeExtension(extension.ExtensionIdentifier));
                        context.RockRidgeIdentifier = extension.ExtensionIdentifier;
                        break;

                    default:
                        extensions.Add(new GenericSuspExtension(extension.ExtensionIdentifier));
                        break;
                    }
                }
            }
            else if (suspRecords.GetEntries(null, "RR") != null)
            {
                // Some ISO creators don't add the 'ER' record for RockRidge, but write the (legacy)
                // RR record anyway
                extensions.Add(new RockRidgeExtension("RRIP_1991A"));
                context.RockRidgeIdentifier = "RRIP_1991A";
            }

            context.SuspExtensions = extensions;
        }
Esempio n. 6
0
        private static int WriteMember(BuildDirectoryMember m, string nameOverride, Encoding nameEnc, byte[] buffer, int offset, Dictionary <BuildDirectoryMember, uint> locationTable, Encoding dataEnc)
        {
            DirectoryRecord dr = new DirectoryRecord();

            dr.FileIdentifier       = m.PickName(nameOverride, nameEnc);
            dr.LocationOfExtent     = locationTable[m];
            dr.DataLength           = (uint)m.GetDataSize(dataEnc);
            dr.RecordingDateAndTime = m.CreationTime;
            dr.Flags = (m is BuildDirectoryInfo) ? FileFlags.Directory : FileFlags.None;
            return(dr.WriteTo(buffer, offset, nameEnc));
        }
Esempio n. 7
0
        public ReaderDirectory(IsoContext context, ReaderDirEntry dirEntry)
            : base(context, dirEntry)
        {
            byte[] buffer = new byte[IsoUtilities.SectorSize];
            Stream extent = new ExtentStream(_context.DataStream, dirEntry.Record.LocationOfExtent, uint.MaxValue, 0, 0);

            _records = new List <ReaderDirEntry>();

            uint totalLength = dirEntry.Record.DataLength;
            uint totalRead   = 0;

            while (totalRead < totalLength)
            {
                int  toRead    = (int)Math.Min(buffer.Length, totalLength - totalRead);
                uint bytesRead = (uint)Utilities.ReadFully(extent, buffer, 0, toRead);
                if (bytesRead != toRead)
                {
                    throw new IOException("Failed to read whole directory");
                }

                totalRead += (uint)bytesRead;

                uint pos = 0;
                while (pos < bytesRead && buffer[pos] != 0)
                {
                    DirectoryRecord dr;
                    uint            length = (uint)DirectoryRecord.ReadFrom(buffer, (int)pos, context.VolumeDescriptor.CharacterEncoding, out dr);

                    if (!IsoUtilities.IsSpecialDirectory(dr))
                    {
                        ReaderDirEntry childDirEntry = new ReaderDirEntry(_context, dr);

                        if (context.SuspDetected && !string.IsNullOrEmpty(context.RockRidgeIdentifier))
                        {
                            if (childDirEntry.SuspRecords == null || !childDirEntry.SuspRecords.HasEntry(context.RockRidgeIdentifier, "RE"))
                            {
                                _records.Add(childDirEntry);
                            }
                        }
                        else
                        {
                            _records.Add(childDirEntry);
                        }
                    }
                    else if (dr.FileIdentifier == "\0")
                    {
                        _self = new ReaderDirEntry(_context, dr);
                    }

                    pos += length;
                }
            }
        }
        public CommonVolumeDescriptor(
            VolumeDescriptorType type,
            byte version,
            uint volumeSpaceSize,
            uint pathTableSize,
            uint typeLPathTableLocation,
            uint typeMPathTableLocation,
            uint rootDirExtentLocation,
            uint rootDirDataLength,
            DateTime buildTime,
            Encoding enc)
            : base(type, version)
        {
            CharacterEncoding = enc;

            SystemIdentifier       = string.Empty;
            VolumeIdentifier       = string.Empty;
            VolumeSpaceSize        = volumeSpaceSize;
            VolumeSetSize          = 1;
            VolumeSequenceNumber   = 1;
            LogicalBlockSize       = IsoUtilities.SectorSize;
            PathTableSize          = pathTableSize;
            TypeLPathTableLocation = typeLPathTableLocation;
            ////OptionalTypeLPathTableLocation = 0;
            TypeMPathTableLocation = typeMPathTableLocation;
            ////OptionalTypeMPathTableLocation = 0;
            RootDirectory = new DirectoryRecord();
            RootDirectory.ExtendedAttributeRecordLength = 0;
            RootDirectory.LocationOfExtent     = rootDirExtentLocation;
            RootDirectory.DataLength           = rootDirDataLength;
            RootDirectory.RecordingDateAndTime = buildTime;
            RootDirectory.Flags                = FileFlags.Directory;
            RootDirectory.FileUnitSize         = 0;
            RootDirectory.InterleaveGapSize    = 0;
            RootDirectory.VolumeSequenceNumber = 1;
            RootDirectory.FileIdentifier       = "\0";
            VolumeSetIdentifier                = string.Empty;
            PublisherIdentifier                = string.Empty;
            DataPreparerIdentifier             = string.Empty;
            ApplicationIdentifier              = string.Empty;
            CopyrightFileIdentifier            = string.Empty;
            AbstractFileIdentifier             = string.Empty;
            BibliographicFileIdentifier        = string.Empty;
            CreationDateAndTime                = buildTime;
            ModificationDateAndTime            = buildTime;
            ExpirationDateAndTime              = DateTime.MinValue;
            EffectiveDateAndTime               = buildTime;
            FileStructureVersion               = 1; // V1
        }
Esempio n. 9
0
 internal uint GetDirectoryRecordSize(Encoding enc)
 {
     return(DirectoryRecord.CalcLength(PickName(null, enc), enc));
 }
        public CommonVolumeDescriptor(
            VolumeDescriptorType type,
            byte version,
            uint volumeSpaceSize,
            uint pathTableSize,
            uint typeLPathTableLocation,
            uint typeMPathTableLocation,
            uint rootDirExtentLocation,
            uint rootDirDataLength,
            DateTime buildTime,
            Encoding enc)
            : base(type, version)
        {
            CharacterEncoding = enc;

            SystemIdentifier = string.Empty;
            VolumeIdentifier = string.Empty;
            VolumeSpaceSize = volumeSpaceSize;
            VolumeSetSize = 1;
            VolumeSequenceNumber = 1;
            LogicalBlockSize = IsoUtilities.SectorSize;
            PathTableSize = pathTableSize;
            TypeLPathTableLocation = typeLPathTableLocation;
            ////OptionalTypeLPathTableLocation = 0;
            TypeMPathTableLocation = typeMPathTableLocation;
            ////OptionalTypeMPathTableLocation = 0;
            RootDirectory = new DirectoryRecord();
            RootDirectory.ExtendedAttributeRecordLength = 0;
            RootDirectory.LocationOfExtent = rootDirExtentLocation;
            RootDirectory.DataLength = rootDirDataLength;
            RootDirectory.RecordingDateAndTime = buildTime;
            RootDirectory.Flags = FileFlags.Directory;
            RootDirectory.FileUnitSize = 0;
            RootDirectory.InterleaveGapSize = 0;
            RootDirectory.VolumeSequenceNumber = 1;
            RootDirectory.FileIdentifier = "\0";
            VolumeSetIdentifier = string.Empty;
            PublisherIdentifier = string.Empty;
            DataPreparerIdentifier = string.Empty;
            ApplicationIdentifier = string.Empty;
            CopyrightFileIdentifier = string.Empty;
            AbstractFileIdentifier = string.Empty;
            BibliographicFileIdentifier = string.Empty;
            CreationDateAndTime = buildTime;
            ModificationDateAndTime = buildTime;
            ExpirationDateAndTime = DateTime.MinValue;
            EffectiveDateAndTime = buildTime;
            FileStructureVersion = 1; // V1
        }
Esempio n. 11
0
        public ReaderDirEntry(IsoContext context, DirectoryRecord dirRecord)
        {
            _context = context;
            _record = dirRecord;
            _fileName = _record.FileIdentifier;

            if (context.SuspDetected && _record.SystemUseData != null)
            {
                _suspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
            }

            if (!string.IsNullOrEmpty(_context.RockRidgeIdentifier))
            {
                // The full name is taken from this record, even if it's a child-link record
                List<SystemUseEntry> nameEntries = _suspRecords.GetEntries(_context.RockRidgeIdentifier, "NM");
                StringBuilder rrName = new StringBuilder();
                if (nameEntries != null && nameEntries.Count > 0)
                {
                    foreach (PosixNameSystemUseEntry nameEntry in nameEntries)
                    {
                        rrName.Append(nameEntry.NameData);
                    }

                    _fileName = rrName.ToString();
                }

                // If this is a Rock Ridge child link, replace the dir record with that from the 'self' record
                // in the child directory.
                ChildLinkSystemUseEntry clEntry = _suspRecords.GetEntry<ChildLinkSystemUseEntry>(_context.RockRidgeIdentifier, "CL");
                if (clEntry != null)
                {
                    _context.DataStream.Position = clEntry.ChildDirLocation * _context.VolumeDescriptor.LogicalBlockSize;
                    byte[] firstSector = Utilities.ReadFully(_context.DataStream, _context.VolumeDescriptor.LogicalBlockSize);

                    DirectoryRecord.ReadFrom(firstSector, 0, _context.VolumeDescriptor.CharacterEncoding, out _record);
                    if (_record.SystemUseData != null)
                    {
                        _suspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
                    }
                }
            }

            _lastAccessTimeUtc = _record.RecordingDateAndTime;
            _lastWriteTimeUtc = _record.RecordingDateAndTime;
            _creationTimeUtc = _record.RecordingDateAndTime;

            if (!string.IsNullOrEmpty(_context.RockRidgeIdentifier))
            {
                FileTimeSystemUseEntry tfEntry = _suspRecords.GetEntry<FileTimeSystemUseEntry>(_context.RockRidgeIdentifier, "TF");

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Access) != 0)
                {
                    _lastAccessTimeUtc = tfEntry.AccessTime;
                }

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Modify) != 0)
                {
                    _lastWriteTimeUtc = tfEntry.ModifyTime;
                }

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Creation) != 0)
                {
                    _creationTimeUtc = tfEntry.CreationTime;
                }
            }
        }
Esempio n. 12
0
 internal static bool IsSpecialDirectory(DirectoryRecord r)
 {
     return(r.FileIdentifier == "\0" || r.FileIdentifier == "\x01");
 }
Esempio n. 13
0
        public ReaderDirEntry(IsoContext context, DirectoryRecord dirRecord)
        {
            _context  = context;
            _record   = dirRecord;
            _fileName = _record.FileIdentifier;

            if (context.SuspDetected && _record.SystemUseData != null)
            {
                _suspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
            }

            if (!string.IsNullOrEmpty(_context.RockRidgeIdentifier))
            {
                // The full name is taken from this record, even if it's a child-link record
                List <SystemUseEntry> nameEntries = _suspRecords.GetEntries(_context.RockRidgeIdentifier, "NM");
                StringBuilder         rrName      = new StringBuilder();
                if (nameEntries != null && nameEntries.Count > 0)
                {
                    foreach (PosixNameSystemUseEntry nameEntry in nameEntries)
                    {
                        rrName.Append(nameEntry.NameData);
                    }

                    _fileName = rrName.ToString();
                }

                // If this is a Rock Ridge child link, replace the dir record with that from the 'self' record
                // in the child directory.
                ChildLinkSystemUseEntry clEntry = _suspRecords.GetEntry <ChildLinkSystemUseEntry>(_context.RockRidgeIdentifier, "CL");
                if (clEntry != null)
                {
                    _context.DataStream.Position = clEntry.ChildDirLocation * _context.VolumeDescriptor.LogicalBlockSize;
                    byte[] firstSector = Utilities.ReadFully(_context.DataStream, _context.VolumeDescriptor.LogicalBlockSize);

                    DirectoryRecord.ReadFrom(firstSector, 0, _context.VolumeDescriptor.CharacterEncoding, out _record);
                    if (_record.SystemUseData != null)
                    {
                        _suspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
                    }
                }
            }

            _lastAccessTimeUtc = _record.RecordingDateAndTime;
            _lastWriteTimeUtc  = _record.RecordingDateAndTime;
            _creationTimeUtc   = _record.RecordingDateAndTime;

            if (!string.IsNullOrEmpty(_context.RockRidgeIdentifier))
            {
                FileTimeSystemUseEntry tfEntry = _suspRecords.GetEntry <FileTimeSystemUseEntry>(_context.RockRidgeIdentifier, "TF");

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Access) != 0)
                {
                    _lastAccessTimeUtc = tfEntry.AccessTime;
                }

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Modify) != 0)
                {
                    _lastWriteTimeUtc = tfEntry.ModifyTime;
                }

                if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Creation) != 0)
                {
                    _creationTimeUtc = tfEntry.CreationTime;
                }
            }
        }
Esempio n. 14
0
 internal static bool IsSpecialDirectory(DirectoryRecord r)
 {
     return r.FileIdentifier == "\0" || r.FileIdentifier == "\x01";
 }
Esempio n. 15
0
        /// <summary>
        /// Initializes a new instance of the VfsCDReader class.
        /// </summary>
        /// <param name="data">The stream to read the ISO image from.</param>
        /// <param name="variantPriorities">Which possible file system variants to use, and with which priority</param>
        /// <param name="hideVersions">Hides version numbers (e.g. ";1") from the end of files</param>
        /// <remarks>
        /// <para>
        /// The implementation considers each of the file system variants in <c>variantProperties</c> and selects
        /// the first which is determined to be present.  In this example Joliet, then Rock Ridge, then vanilla
        /// Iso9660 will be considered:
        /// </para>
        /// <code lang="cs">
        /// VfsCDReader(stream, new Iso9660Variant[] {Joliet, RockRidge, Iso9660}, true);
        /// </code>
        /// <para>The Iso9660 variant should normally be specified as the final entry in the list.  Placing it earlier
        /// in the list will effectively mask later items and not including it may prevent some ISOs from being read.</para>
        /// </remarks>
        public VfsCDReader(Stream data, Iso9660Variant[] variantPriorities, bool hideVersions)
            : base(new DiscFileSystemOptions())
        {
            _data         = data;
            _hideVersions = hideVersions;

            long vdpos = 0x8000; // Skip lead-in

            byte[] buffer = new byte[IsoUtilities.SectorSize];

            long pvdPos = 0;
            long svdPos = 0;

            BaseVolumeDescriptor bvd;

            do
            {
                data.Position = vdpos;
                int numRead = data.Read(buffer, 0, IsoUtilities.SectorSize);
                if (numRead != IsoUtilities.SectorSize)
                {
                    break;
                }

                bvd = new BaseVolumeDescriptor(buffer, 0);
                switch (bvd.VolumeDescriptorType)
                {
                case VolumeDescriptorType.Boot:
                    _bootVolDesc = new BootVolumeDescriptor(buffer, 0);
                    if (_bootVolDesc.SystemId != BootVolumeDescriptor.ElToritoSystemIdentifier)
                    {
                        _bootVolDesc = null;
                    }

                    break;

                case VolumeDescriptorType.Primary:     // Primary Vol Descriptor
                    pvdPos = vdpos;
                    break;

                case VolumeDescriptorType.Supplementary:     // Supplementary Vol Descriptor
                    svdPos = vdpos;
                    break;

                case VolumeDescriptorType.Partition:     // Volume Partition Descriptor
                    break;

                case VolumeDescriptorType.SetTerminator:     // Volume Descriptor Set Terminator
                    break;
                }

                vdpos += IsoUtilities.SectorSize;
            }while (bvd.VolumeDescriptorType != VolumeDescriptorType.SetTerminator);

            _activeVariant = Iso9660Variant.None;
            foreach (var variant in variantPriorities)
            {
                switch (variant)
                {
                case Iso9660Variant.Joliet:
                    if (svdPos != 0)
                    {
                        data.Position = svdPos;
                        data.Read(buffer, 0, IsoUtilities.SectorSize);
                        var volDesc = new SupplementaryVolumeDescriptor(buffer, 0);

                        Context = new IsoContext {
                            VolumeDescriptor = volDesc, DataStream = _data
                        };
                        RootDirectory  = new ReaderDirectory(Context, new ReaderDirEntry(Context, volDesc.RootDirectory));
                        _activeVariant = Iso9660Variant.Iso9660;
                    }

                    break;

                case Iso9660Variant.RockRidge:
                case Iso9660Variant.Iso9660:
                    if (pvdPos != 0)
                    {
                        data.Position = pvdPos;
                        data.Read(buffer, 0, IsoUtilities.SectorSize);
                        var volDesc = new PrimaryVolumeDescriptor(buffer, 0);

                        IsoContext context = new IsoContext {
                            VolumeDescriptor = volDesc, DataStream = _data
                        };
                        DirectoryRecord rootSelfRecord = ReadRootSelfRecord(context);

                        InitializeSusp(context, rootSelfRecord);

                        if (variant == Iso9660Variant.Iso9660 ||
                            (variant == Iso9660Variant.RockRidge && !string.IsNullOrEmpty(context.RockRidgeIdentifier)))
                        {
                            Context        = context;
                            RootDirectory  = new ReaderDirectory(context, new ReaderDirEntry(context, rootSelfRecord));
                            _activeVariant = variant;
                        }
                    }

                    break;
                }

                if (_activeVariant != Iso9660Variant.None)
                {
                    break;
                }
            }

            if (_activeVariant == Iso9660Variant.None)
            {
                throw new IOException("None of the permitted ISO9660 file system variants was detected");
            }
        }