コード例 #1
0
        private RawTOCEntry EmitRawTOCEntry(ATOCEntry entry)
        {
            BCD2 tno, ino;

            //this should actually be zero. im not sure if this is stored as BCD2 or not
            tno = BCD2.FromDecimal(entry.TrackNo);

            //these are special values.. I think, taken from this:
            //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
            //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
            //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
            ino = BCD2.FromDecimal(entry.Point);
            if (entry.Point == 0xA0)
            {
                ino.BCDValue = 0xA0;
            }
            else if (entry.Point == 0xA1)
            {
                ino.BCDValue = 0xA1;
            }
            else if (entry.Point == 0xA2)
            {
                ino.BCDValue = 0xA2;
            }

            // get ADR & Control from ADR_Control byte
            byte adrc    = Convert.ToByte(entry.ADR_Control);
            var  Control = adrc & 0x0F;
            var  ADR     = adrc >> 4;

            var q = new SubchannelQ
            {
                q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)),
                q_tno    = tno,
                q_index  = ino,
                min      = BCD2.FromDecimal(entry.AMin),
                sec      = BCD2.FromDecimal(entry.ASec),
                frame    = BCD2.FromDecimal(entry.AFrame),
                zero     = (byte)entry.Zero,
                ap_min   = BCD2.FromDecimal(entry.PMin),
                ap_sec   = BCD2.FromDecimal(entry.PSec),
                ap_frame = BCD2.FromDecimal(entry.PFrame),
                q_crc    = 0,              //meaningless
            };

            return(new RawTOCEntry {
                QData = q
            });
        }
コード例 #2
0
        public AFile Parse(Stream stream)
        {
            EndianBitConverter bc    = EndianBitConverter.CreateForLittleEndian();
            EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian();
            bool isDvd = false;

            AFile aFile = new AFile();

            aFile.MDSPath = (stream as FileStream).Name;

            stream.Seek(0, SeekOrigin.Begin);

            // check whether the header in the mds file is long enough
            if (stream.Length < 88)
            {
                throw new MDSParseException("Malformed MDS format: The descriptor file does not appear to be long enough.");
            }

            // parse header
            aFile.Header = aFile.Header.Parse(stream);

            // check version to make sure this is only v1.x
            // currently NO support for version 2.x

            if (aFile.Header.Version[0] > 1)
            {
                throw new MDSParseException("MDS Parse Error: Only MDS version 1.x is supported!\nDetected version: " + aFile.Header.Version[0] + "." + aFile.Header.Version[1]);
            }

            // parse sessions
            Dictionary <int, ASession> aSessions = new Dictionary <int, ASession>();

            stream.Seek(aFile.Header.SessionOffset, SeekOrigin.Begin);
            for (int se = 0; se < aFile.Header.SessionCount; se++)
            {
                byte[] sessionHeader = new byte[24];
                stream.Read(sessionHeader, 0, 24);
                //sessionHeader.Reverse().ToArray();

                ASession session = new ASession();

                session.SessionStart   = bc.ToInt32(sessionHeader.Take(4).ToArray());
                session.SessionEnd     = bc.ToInt32(sessionHeader.Skip(4).Take(4).ToArray());
                session.SessionNumber  = bc.ToInt16(sessionHeader.Skip(8).Take(2).ToArray());
                session.AllBlocks      = sessionHeader[10];
                session.NonTrackBlocks = sessionHeader[11];
                session.FirstTrack     = bc.ToInt16(sessionHeader.Skip(12).Take(2).ToArray());
                session.LastTrack      = bc.ToInt16(sessionHeader.Skip(14).Take(2).ToArray());
                session.TrackOffset    = bc.ToInt32(sessionHeader.Skip(20).Take(4).ToArray());


                //mdsf.Sessions.Add(session);
                aSessions.Add(session.SessionNumber, session);
            }

            long footerOffset = 0;

            // parse track blocks
            Dictionary <int, ATrack> aTracks = new Dictionary <int, ATrack>();

            // iterate through each session block
            foreach (ASession session in aSessions.Values)
            {
                stream.Seek(session.TrackOffset, SeekOrigin.Begin);
                //Dictionary<int, ATrack> sessionToc = new Dictionary<int, ATrack>();

                // iterate through every block specified in each session
                for (int bl = 0; bl < session.AllBlocks; bl++)
                {
                    byte[] trackHeader;
                    ATrack track = new ATrack();

                    trackHeader = new byte[80];

                    stream.Read(trackHeader, 0, 80);

                    track.Mode         = trackHeader[0];
                    track.SubMode      = trackHeader[1];
                    track.ADR_Control  = trackHeader[2];
                    track.TrackNo      = trackHeader[3];
                    track.Point        = trackHeader[4];
                    track.AMin         = trackHeader[5];
                    track.ASec         = trackHeader[6];
                    track.AFrame       = trackHeader[7];
                    track.Zero         = trackHeader[8];
                    track.PMin         = trackHeader[9];
                    track.PSec         = trackHeader[10];
                    track.PFrame       = trackHeader[11];
                    track.ExtraOffset  = bc.ToInt32(trackHeader.Skip(12).Take(4).ToArray());
                    track.SectorSize   = bc.ToInt16(trackHeader.Skip(16).Take(2).ToArray());
                    track.PLBA         = bc.ToInt32(trackHeader.Skip(36).Take(4).ToArray());
                    track.StartOffset  = BitConverter.ToUInt64(trackHeader.Skip(40).Take(8).ToArray(), 0);
                    track.Files        = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray());
                    track.FooterOffset = bc.ToInt32(trackHeader.Skip(52).Take(4).ToArray());

                    if (track.Mode == 0x02)
                    {
                        isDvd = true;
                        throw new MDSParseException("DVD Detected. Not currently supported!");
                    }


                    // check for track extra block - this can probably be handled in a separate loop,
                    // but I'll just store the current stream position then seek forward to the extra block for this track
                    Int64 currPos = stream.Position;

                    // Only CDs have extra blocks - for DVDs ExtraOffset = track length
                    if (track.ExtraOffset > 0 && !isDvd)
                    {
                        byte[] extHeader = new byte[8];
                        stream.Seek(track.ExtraOffset, SeekOrigin.Begin);
                        stream.Read(extHeader, 0, 8);
                        track.ExtraBlock.Pregap  = bc.ToInt32(extHeader.Take(4).ToArray());
                        track.ExtraBlock.Sectors = bc.ToInt32(extHeader.Skip(4).Take(4).ToArray());
                        stream.Seek(currPos, SeekOrigin.Begin);
                    }
                    else if (isDvd == true)
                    {
                        track.ExtraBlock.Sectors = track.ExtraOffset;
                    }

                    // read the footer/filename block for this track
                    currPos = stream.Position;
                    long numOfFilenames = track.Files;
                    for (long fi = 1; fi <= numOfFilenames; fi++)
                    {
                        // skip leadin/out info tracks
                        if (track.FooterOffset == 0)
                        {
                            continue;
                        }

                        byte[] foot = new byte[16];
                        stream.Seek(track.FooterOffset, SeekOrigin.Begin);
                        stream.Read(foot, 0, 16);

                        AFooter f = new AFooter();
                        f.FilenameOffset = bc.ToInt32(foot.Take(4).ToArray());
                        f.WideChar       = bc.ToInt32(foot.Skip(4).Take(4).ToArray());
                        track.FooterBlocks.Add(f);
                        track.FooterBlocks = track.FooterBlocks.Distinct().ToList();

                        // parse the filename string
                        string fileName = "*.mdf";
                        if (f.FilenameOffset > 0)
                        {
                            // filename offset is present
                            stream.Seek(f.FilenameOffset, SeekOrigin.Begin);
                            byte[] fname;

                            if (numOfFilenames == 1)
                            {
                                if (aFile.Header.DPMOffset == 0)
                                {
                                    // filename is in the remaining space to EOF
                                    fname = new byte[stream.Length - stream.Position];
                                }
                                else
                                {
                                    // filename is in the remaining space to EOF + dpm offset
                                    fname = new byte[aFile.Header.DPMOffset - stream.Position];
                                }
                            }

                            else
                            {
                                // looks like each filename string is 6 bytes with a trailing \0
                                fname = new byte[6];
                            }


                            // read the filename
                            stream.Read(fname, 0, fname.Length);

                            // if widechar is 1 filename is stored using 16-bit, otherwise 8-bit is used
                            if (f.WideChar == 1)
                            {
                                fileName = Encoding.Unicode.GetString(fname).TrimEnd('\0');
                            }
                            else
                            {
                                fileName = Encoding.Default.GetString(fname).TrimEnd('\0');
                            }
                        }

                        else
                        {
                            // assume an MDF file with the same name as the MDS
                        }

                        string dir = Path.GetDirectoryName(aFile.MDSPath);

                        if (f.FilenameOffset == 0 ||
                            string.Compare(fileName, "*.mdf", StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            fileName = dir + @"\" + Path.GetFileNameWithoutExtension(aFile.MDSPath) + ".mdf";
                        }
                        else
                        {
                            fileName = dir + @"\" + fileName;
                        }

                        track.ImageFileNamePaths.Add(fileName);
                        track.ImageFileNamePaths = track.ImageFileNamePaths.Distinct().ToList();
                    }

                    stream.Position = currPos;


                    aTracks.Add(track.Point, track);
                    aFile.Tracks.Add(track);

                    if (footerOffset == 0)
                    {
                        footerOffset = track.FooterOffset;
                    }
                }
            }


            // build custom session object
            aFile.ParsedSession = new List <Session>();
            foreach (var s in aSessions.Values)
            {
                Session session = new Session();
                ATrack  startTrack;
                ATrack  endTrack;

                if (!aTracks.TryGetValue(s.FirstTrack, out startTrack))
                {
                    break;
                }

                if (!aTracks.TryGetValue(s.LastTrack, out endTrack))
                {
                    break;
                }

                session.StartSector     = startTrack.PLBA;
                session.StartTrack      = s.FirstTrack;
                session.SessionSequence = s.SessionNumber;
                session.EndSector       = endTrack.PLBA + endTrack.ExtraBlock.Sectors - 1;
                session.EndTrack        = s.LastTrack;

                aFile.ParsedSession.Add(session);
            }

            // now build the TOC object
            foreach (var se in aFile.ParsedSession)
            {
                // get the first and last tracks
                int sTrack = se.StartTrack;
                int eTrack = se.EndTrack;

                // get list of all tracks from aTracks for this session
                var tracks = (from a in aTracks.Values
                              where a.TrackNo >= sTrack || a.TrackNo <= eTrack
                              orderby a.TrackNo
                              select a).ToList();

                // create the TOC entries
                foreach (var t in tracks)
                {
                    ATOCEntry toc = new ATOCEntry(t.Point);
                    toc.ADR_Control        = t.ADR_Control;
                    toc.AFrame             = t.AFrame;
                    toc.AMin               = t.AMin;
                    toc.ASec               = t.ASec;
                    toc.EntryNum           = t.TrackNo;
                    toc.PFrame             = t.PFrame;
                    toc.PLBA               = Convert.ToInt32(t.PLBA);
                    toc.PMin               = t.PMin;
                    toc.Point              = t.Point;
                    toc.PSec               = t.PSec;
                    toc.SectorSize         = t.SectorSize;
                    toc.Zero               = t.Zero;
                    toc.TrackOffset        = Convert.ToInt64(t.StartOffset);
                    toc.Session            = se.SessionSequence;
                    toc.ImageFileNamePaths = t.ImageFileNamePaths;
                    toc.ExtraBlock         = t.ExtraBlock;
                    toc.BlobIndex          = t.BlobIndex;
                    aFile.TOCEntries.Add(toc);
                }
            }

            return(aFile);
        }