| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 | #pragma warning disable CS1591using System;using System.Collections.Generic;using System.Globalization;using System.IO;using System.Linq;namespace DvdLib.Ifo{    public class Dvd    {        private readonly ushort _titleSetCount;        public readonly List<Title> Titles;        private ushort _titleCount;        public readonly Dictionary<ushort, string> VTSPaths = new Dictionary<ushort, string>();        public Dvd(string path)        {            Titles = new List<Title>();            var allFiles = new DirectoryInfo(path).GetFiles(path, SearchOption.AllDirectories);            var vmgPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.IFO", StringComparison.OrdinalIgnoreCase)) ??                allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.BUP", StringComparison.OrdinalIgnoreCase));            if (vmgPath == null)            {                foreach (var ifo in allFiles)                {                    if (!string.Equals(ifo.Extension, ".ifo", StringComparison.OrdinalIgnoreCase))                    {                        continue;                    }                    var nums = ifo.Name.Split('_', StringSplitOptions.RemoveEmptyEntries);                    if (nums.Length >= 2 && ushort.TryParse(nums[1], out var ifoNumber))                    {                        ReadVTS(ifoNumber, ifo.FullName);                    }                }            }            else            {                using (var vmgFs = new FileStream(vmgPath.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))                {                    using (var vmgRead = new BigEndianBinaryReader(vmgFs))                    {                        vmgFs.Seek(0x3E, SeekOrigin.Begin);                        _titleSetCount = vmgRead.ReadUInt16();                        // read address of TT_SRPT                        vmgFs.Seek(0xC4, SeekOrigin.Begin);                        uint ttSectorPtr = vmgRead.ReadUInt32();                        vmgFs.Seek(ttSectorPtr * 2048, SeekOrigin.Begin);                        ReadTT_SRPT(vmgRead);                    }                }                for (ushort titleSetNum = 1; titleSetNum <= _titleSetCount; titleSetNum++)                {                    ReadVTS(titleSetNum, allFiles);                }            }        }        private void ReadTT_SRPT(BinaryReader read)        {            _titleCount = read.ReadUInt16();            read.BaseStream.Seek(6, SeekOrigin.Current);            for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)            {                var t = new Title(titleNum);                t.ParseTT_SRPT(read);                Titles.Add(t);            }        }        private void ReadVTS(ushort vtsNum, IReadOnlyList<FileInfo> allFiles)        {            var filename = string.Format(CultureInfo.InvariantCulture, "VTS_{0:00}_0.IFO", vtsNum);            var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??                allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));            if (vtsPath == null)            {                throw new FileNotFoundException("Unable to find VTS IFO file");            }            ReadVTS(vtsNum, vtsPath.FullName);        }        private void ReadVTS(ushort vtsNum, string vtsPath)        {            VTSPaths[vtsNum] = vtsPath;            using (var vtsFs = new FileStream(vtsPath, FileMode.Open, FileAccess.Read, FileShare.Read))            {                using (var vtsRead = new BigEndianBinaryReader(vtsFs))                {                    // Read VTS_PTT_SRPT                    vtsFs.Seek(0xC8, SeekOrigin.Begin);                    uint vtsPttSrptSecPtr = vtsRead.ReadUInt32();                    uint baseAddr = (vtsPttSrptSecPtr * 2048);                    vtsFs.Seek(baseAddr, SeekOrigin.Begin);                    ushort numTitles = vtsRead.ReadUInt16();                    vtsRead.ReadUInt16();                    uint endaddr = vtsRead.ReadUInt32();                    uint[] offsets = new uint[numTitles];                    for (ushort titleNum = 0; titleNum < numTitles; titleNum++)                    {                        offsets[titleNum] = vtsRead.ReadUInt32();                    }                    for (uint titleNum = 0; titleNum < numTitles; titleNum++)                    {                        uint chapNum = 1;                        vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);                        var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));                        if (t == null)                        {                            continue;                        }                        do                        {                            t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum));                            if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1]))                            {                                break;                            }                            chapNum++;                        }                        while (vtsFs.Position < (baseAddr + endaddr));                    }                    // Read VTS_PGCI                    vtsFs.Seek(0xCC, SeekOrigin.Begin);                    uint vtsPgciSecPtr = vtsRead.ReadUInt32();                    vtsFs.Seek(vtsPgciSecPtr * 2048, SeekOrigin.Begin);                    long startByte = vtsFs.Position;                    ushort numPgcs = vtsRead.ReadUInt16();                    vtsFs.Seek(6, SeekOrigin.Current);                    for (ushort pgcNum = 1; pgcNum <= numPgcs; pgcNum++)                    {                        byte pgcCat = vtsRead.ReadByte();                        bool entryPgc = (pgcCat & 0x80) != 0;                        uint titleNum = (uint)(pgcCat & 0x7F);                        vtsFs.Seek(3, SeekOrigin.Current);                        uint vtsPgcOffset = vtsRead.ReadUInt32();                        var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));                        if (t != null)                        {                            t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);                        }                    }                }            }        }    }}
 |