csharp/13xforever/ps3-disc-dumper/IrdLibraryClient/IrdFormat/IsoHeaderParser.cs

IsoHeaderParser.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DiscUtils.Iso9660;
using DiscUtils.Streams;

namespace IrdLibraryClient.IrdFormat
{
    public static clast IsoHeaderParser
    {
        public static (List files, List dirs) GetFilesystemStructure(this CDReader reader)
        {
            var fsObjects = reader.GetFileSystemEntries(reader.Root.FullName).ToList();
            var nextLevel = new List();
            var filePaths = new List();
            var dirPaths = new List();
            while (fsObjects.Any())
            {
                foreach (var path in fsObjects)
                {
                    if (reader.FileExists(path))
                        filePaths.Add(path);
                    else if (reader.DirectoryExists(path))
                    {
                        dirPaths.Add(path);
                        nextLevel.AddRange(reader.GetFileSystemEntries(path));
                    }
                    else
                        Log.Warn($"Unknown filesystem object: {path}");
                }
                (fsObjects, nextLevel) = (nextLevel, fsObjects);
                nextLevel.Clear();
            }
            
            var filenames = filePaths.Distinct().Select(n => n.TrimStart('\\')).ToList();
            var dirnames = dirPaths.Distinct().Select(n => n.TrimStart('\\')).OrderByDescending(n => n.Length).ToList();
            var deepestDirnames = new List();
            foreach (var dirname in dirnames)
            {
                var tmp = dirname + "\\";
                if (deepestDirnames.Any(n => n.StartsWith(tmp)))
                    continue;
                
                deepestDirnames.Add(dirname);
            }
            dirnames = deepestDirnames.OrderBy(n => n).ToList();
            var dirnamesWithFiles = filenames.Select(Path.GetDirectoryName).Distinct().ToList();
            var emptydirs = dirnames.Except(dirnamesWithFiles).ToList();

            var fileList = new List();
            foreach (var filename in filenames)
            {
                var clusterRange = reader.PathToClusters(filename);
                if (clusterRange.Length != 1)
                    Log.Warn($"{filename} is split in {clusterRange.Length} ranges");
                if (filename.EndsWith("."))
                    Log.Warn($"Fixing potential mastering error in {filename}");
                fileList.Add(new FileRecord(filename.TrimEnd('.'), clusterRange.Min(r => r.Offset), reader.GetFileLength(filename)));
            }
            fileList = fileList.OrderBy(r => r.StartSector).ToList();
            return (files: fileList, dirs: emptydirs);
        }

        public static List GetUnprotectedRegions(this Stream discStream)
        {
            var result = new List();
            discStream.Seek(0, SeekOrigin.Begin);
            var reader = new BigEndianDataReader(discStream);
            var regionCount = reader.ReadInt32();
            Log.Trace($"Found {regionCount} encrypted regions");

            var unk = reader.ReadUInt32(); // 0?
            if (unk != 0)
                Log.Debug($"Unk in sector description was {unk:x16}");

            for (var i = 0; i < regionCount; i++)
            {
                var start = reader.ReadInt32();
                var end = reader.ReadInt32();
                Log.Trace($"Unprotected region: {start:x8}-{end:x8}");
                result.Add((start, end));
            }
            return result;
        }
    }

    public clast FileRecord
    {
        public FileRecord(string filename, long startSector, long length)
        {
            Filename = filename;
            StartSector = startSector;
            Length = length;
        }

        public string Filename { get; }
        public long StartSector { get; }
        public long Length { get; }
    }
}