public static NativePathEntry FromReader(BinaryReader reader)
            {
                NativePathEntry npe = new NativePathEntry();

                npe.ChildLengths = new Dictionary <string, int>();

                byte nameLength = reader.ReadByte();

                byte extraSectors = reader.ReadByte();

                Debug.Assert(extraSectors == 0);

                npe.FirstSector = reader.ReadInt32();
                npe.ParentEntry = reader.ReadInt16() - 1;                 // Fixup because we are 0 based

                if (reader.PeekChar() == 0)
                {
                    //reader.BaseStream.Seek( nameLength, SeekOrigin.Current );
                    npe.IsRoot = true;
                    reader.ReadByte();
                }
                else
                {
                    npe.Name = ReadString(reader, nameLength);
                }

                if (nameLength % 2 == 1)
                {
                    reader.BaseStream.Seek(1, SeekOrigin.Current);
                }

                return(npe);
            }
            public static NativePrimaryDescriptor?FromStream(BinaryReader reader)
            {
                NativePrimaryDescriptor npd = new NativePrimaryDescriptor();

                // Starts at logical block 16 (0x8000)
                reader.BaseStream.Seek(16 * 2048, SeekOrigin.Begin);

                reader.BaseStream.Seek(1, SeekOrigin.Current);
                string magic = ReadString(reader, 5);

                if (magic != "CD001")
                {
                    return(null);
                }

                reader.BaseStream.Seek(2, SeekOrigin.Current);
                npd.SystemID = ReadString(reader, 32);
                npd.VolumeID = ReadString(reader, 32);

                reader.BaseStream.Seek(8, SeekOrigin.Current);
                npd.SectorCount = reader.ReadInt32();

                reader.BaseStream.Seek(4 + 32 + 4 + 4, SeekOrigin.Current);
                npd.SectorSize = reader.ReadInt16();

                reader.BaseStream.Seek(2, SeekOrigin.Current);
                npd.PathTableLength = reader.ReadInt32();

                reader.BaseStream.Seek(4, SeekOrigin.Current);
                npd.PathTableStart    = reader.ReadInt32();
                npd.AltPathTableStart = reader.ReadInt32();

                reader.BaseStream.Seek(8, SeekOrigin.Current);
                long            x   = reader.BaseStream.Position;
                NativePathEntry npe = NativePathEntry.FromReader(reader);

                Debug.Assert(npe != null);
                npd.Root = npe;
                long z = reader.BaseStream.Position - x;

                reader.BaseStream.Seek(34 - z, SeekOrigin.Current);

                npd.VolumeName = ReadString(reader, 128);
                npd.Publisher  = ReadString(reader, 128);
                reader.BaseStream.Seek(128, SeekOrigin.Current);
                npd.Application = ReadString(reader, 128);

                reader.BaseStream.Seek(37 + 37 + 37, SeekOrigin.Current);
                string creationString = ReadString(reader, 17);

                npd.Created = ParseDate(creationString);

                // Seek to the end
                reader.BaseStream.Seek(17 * 2048, SeekOrigin.Begin);

                return(npd);
            }
        protected MediaFolder ParseIsoFileSystem(string path, bool minimalCache)
        {
            Debug.Assert(path != null);
            Debug.Assert(File.Exists(path) == true);

            if (File.Exists(path) == false)
            {
                return(null);
            }

            using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    NativePrimaryDescriptor?npdv = NativePrimaryDescriptor.FromStream(reader);
                    Debug.Assert(npdv != null);
                    if (npdv == null)
                    {
                        return(null);
                    }
                    NativePrimaryDescriptor npd = npdv.Value;

                    List <NativePathEntry> npes = new List <NativePathEntry>();
                    stream.Seek(npd.PathTableStart * 2048, SeekOrigin.Begin);
                    while (stream.Position < (npd.PathTableStart * 2048) + npd.PathTableLength)
                    {
                        NativePathEntry npe = NativePathEntry.FromReader(reader);
                        if (npe == null)
                        {
                            continue;
                        }

                        npes.Add(npe);
                    }

                    List <MediaFolder> folders = new List <MediaFolder>(npes.Count);
                    for (int n = 0; n < npes.Count; n++)
                    {
                        NativePathEntry npe = npes[n];

                        MediaFolder current = null;
                        MediaFolder parent  = null;
                        if (npe.IsRoot == false)
                        {
                            parent = folders[npe.ParentEntry];
                        }

                        if (npe.Length == 0)
                        {
                            // Look in parent for length
                            if (parent != null)
                            {
                                NativePathEntry pe = npes[npe.ParentEntry];
                                npe.Length = pe.ChildLengths[npe.Name];
                            }
                            else
                            {
                                npe.Length = 2048;
                            }
                        }

                        int m = 0;
                        for (int s = 0; s < npe.Length / 2048; s++)
                        {
                            stream.Seek((npe.FirstSector + s) * 2048, SeekOrigin.Begin);
                            while (true)
                            {
                                NativeEntry?nev = NativeEntry.FromReader(reader);
                                if (nev == null)
                                {
                                    break;
                                }
                                NativeEntry ne = nev.Value;

                                if (m == 0)
                                {
                                    // '.' this dir
                                    MediaItemAttributes attributes = MediaItemAttributes.Normal;
                                    if ((ne.Flags & NativeEntryFlags.Hidden) == NativeEntryFlags.Hidden)
                                    {
                                        attributes |= MediaItemAttributes.Hidden;
                                    }
                                    current = new MediaFolder(this, parent, npe.Name, attributes, ne.Timestamp);
                                    folders.Add(current);
                                }
                                else if (m == 1)
                                {
                                    // '..' parent dir - ignored
                                }
                                else
                                {
                                    // Child
                                    if ((ne.Flags & NativeEntryFlags.Directory) == NativeEntryFlags.Directory)
                                    {
                                        // Directories are handled when it is their turn to be added
                                        // EXCEPT for size, which we need to get now and store back
                                        // At this time in the code, we have all dirs prior to the one whose length
                                        // we just got - since we have already added ourselves, we know we have its
                                        // parent too
                                        npe.ChildLengths.Add(ne.Name, ne.Length);
                                    }
                                    else
                                    {
                                        MediaItemAttributes attributes = MediaItemAttributes.Normal;
                                        if ((ne.Flags & NativeEntryFlags.Hidden) == NativeEntryFlags.Hidden)
                                        {
                                            attributes |= MediaItemAttributes.Hidden;
                                        }

                                        long lbn = ne.FirstSector /* * 2048*/;

                                        MediaFile file = new MediaFile(this, current, ne.Name, attributes, ne.Timestamp, lbn * 2048, ne.Length);

                                        //Log.WriteLine(Verbosity.Normal, Feature.Bios, "{0} = {1}", ne.Name, lbn);
                                        // Pretty sure this is wrong, but it shouldn't matter
                                        Debug.Assert(_lbnLookup.ContainsKey(lbn) == false);
                                        _lbnLookup[lbn] = file;
                                    }
                                }
                                m++;

                                if ((ne.Flags & NativeEntryFlags.LastEntry) == NativeEntryFlags.LastEntry)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    return(folders[0]);
                }
        }
            public static NativePathEntry FromReader( BinaryReader reader )
            {
                NativePathEntry npe = new NativePathEntry();
                npe.ChildLengths = new Dictionary<string, int>();

                byte nameLength = reader.ReadByte();

                byte extraSectors = reader.ReadByte();
                Debug.Assert( extraSectors == 0 );

                npe.FirstSector = reader.ReadInt32();
                npe.ParentEntry = reader.ReadInt16() - 1; // Fixup because we are 0 based

                if( reader.PeekChar() == 0 )
                {
                    //reader.BaseStream.Seek( nameLength, SeekOrigin.Current );
                    npe.IsRoot = true;
                    reader.ReadByte();
                }
                else
                    npe.Name = ReadString( reader, nameLength );

                if( nameLength % 2 == 1 )
                    reader.BaseStream.Seek( 1, SeekOrigin.Current );

                return npe;
            }