예제 #1
0
        public static void LoadSRS(SortedList <int, TrackData> tracks, ref FileData file, FileInfo inFile)
        {
            using (EbmlReader rdr = new EbmlReader(inFile.FullName, EbmlReadMode.SRS))
            {
                bool done = false;
                while (!done && rdr.Read())
                {
                    switch (rdr.ElementType)
                    {
                    case EbmlElementType.Segment:
                    case EbmlElementType.ReSample:
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.ReSampleFile:
                        byte[] buff = rdr.ReadContents();
                        file = new FileData(buff);
                        break;

                    case EbmlElementType.ReSampleTrack:
                        buff = rdr.ReadContents();
                        TrackData track = new TrackData(buff);
                        tracks.Add(track.TrackNumber, track);
                        break;

                    case EbmlElementType.Cluster:
                    case EbmlElementType.AttachmentList:
                        // if we get to either of these elements, we've passed the interesting part of the file, so bail out
                        rdr.SkipContents();
                        done = true;
                        break;

                    default:
                        rdr.SkipContents();
                        break;
                    }
                }
            }
        }
예제 #2
0
 public static void LoadSRS(SortedList <int, TrackData> tracks, ref FileData file, FileInfo inFile)
 {
     using (RiffReader rdr = new RiffReader(inFile.FullName, RiffReadMode.SRS))
     {
         bool done = false;
         while (!done && rdr.Read())
         {
             if (rdr.ChunkType == RiffChunkType.List)
             {
                 rdr.MoveToChild();
             }
             else
             {
                 if (rdr.Chunk.FourCC == "SRSF")                         // resample file
                 {
                     byte[] buff = rdr.ReadContents();
                     file = new FileData(buff);
                 }
                 else if (rdr.Chunk.FourCC == "SRST")                         // resample track
                 {
                     byte[]    buff  = rdr.ReadContents();
                     TrackData track = new TrackData(buff);
                     tracks.Add(track.TrackNumber, track);
                 }
                 else if (rdr.ChunkType == RiffChunkType.Movi)
                 {
                     // if we get here in load mode, we have already got what we need, so bail out
                     done = true;
                     continue;
                 }
                 else
                 {
                     rdr.SkipContents();
                 }
             }
         }
     }
 }
예제 #3
0
        public static FileData RebuildSample(FileData file, SortedList <int, TrackData> tracks, Dictionary <string, AttachmentData> attachments, FileInfo srsFile, DirectoryInfo outDir)
        {
            uint crc = Crc32.StartValue;

            using (EbmlReader rdr = new EbmlReader(srsFile.FullName, EbmlReadMode.SRS))
                using (FileStream fsOut = new FileStream(Path.Combine(outDir.FullName, file.Name), FileMode.Create))
                {
                    string currentAttachment = null;
                    int    clustercount      = 0;
                    while (rdr.Read())
                    {
                        // the ReSample element is the only part of the SRS file we don't want copied into the new sample.
                        if (rdr.ElementType == EbmlElementType.ReSample)
                        {
                            rdr.SkipContents();
                            continue;
                        }

                        fsOut.Write(rdr.Element.RawHeader, 0, rdr.Element.RawHeader.Length);
                        crc = Crc32.GetCrc(crc, rdr.Element.RawHeader);

                        switch (rdr.ElementType)
                        {
                        case EbmlElementType.Segment:
                        case EbmlElementType.BlockGroup:
                        case EbmlElementType.AttachmentList:
                        case EbmlElementType.Attachment:
                            // these elements have no useful info of their own, but we want to step into them to examine their children
                            rdr.MoveToChild();
                            break;

                        case EbmlElementType.Cluster:
                            // simple progress indicator since this can take a while (cluster is good because they're about 1mb each)
                            Console.Write("\b{0}", Program.spinners[clustercount++ % Program.spinners.Length]);
                            rdr.MoveToChild();
                            break;

                        case EbmlElementType.AttachedFileName:
                            byte[] buff = rdr.ReadContents();
                            fsOut.Write(buff, 0, buff.Length);
                            crc = Crc32.GetCrc(crc, buff);
                            currentAttachment = Encoding.UTF8.GetString(buff);
                            break;

                        case EbmlElementType.AttachedFileData:
                            AttachmentData attachment = attachments[currentAttachment];
                            // restore data from extracted attachments
                            buff = new byte[rdr.Element.Length];
                            attachment.AttachmentFile.Read(buff, 0, buff.Length);
                            fsOut.Write(buff, 0, buff.Length);
                            crc = Crc32.GetCrc(crc, buff);
                            if ((file.Flags & FileData.FileDataFlags.AttachmentsRemoved) != 0)
                            {
                                rdr.MoveToChild();                                  // really means do nothing in this case
                            }
                            else
                            {
                                rdr.SkipContents();
                            }
                            break;

                        case EbmlElementType.Block:
                            TrackData track = tracks[rdr.Block.TrackNumber];
                            // restore data from extracted tracks
                            buff = new byte[rdr.Block.Length];
                            track.TrackFile.Read(buff, 0, buff.Length);
                            fsOut.Write(rdr.Block.RawBlockHeader, 0, rdr.Block.RawBlockHeader.Length);
                            crc = Crc32.GetCrc(crc, rdr.Block.RawBlockHeader);
                            fsOut.Write(buff, 0, buff.Length);
                            crc = Crc32.GetCrc(crc, buff);
                            rdr.MoveToChild();                              // really means do nothing in this case
                            break;

                        default:
                            // anything not caught above is considered metadata, so we copy it as is
                            buff = rdr.ReadContents();
                            fsOut.Write(buff, 0, buff.Length);
                            crc = Crc32.GetCrc(crc, buff);
                            break;
                        }
                    }
                }
            Console.Write('\b');

            FileData newFile = new FileData(Path.Combine(outDir.FullName, file.Name));

            newFile.Crc32 = ~crc;

            return(newFile);
        }
예제 #4
0
        public static void ExtractSampleStreams(SortedList <int, TrackData> tracks, Dictionary <string, AttachmentData> attachments, FileData file, FileInfo inFile, DirectoryInfo outDir)
        {
            Stream fs;

            if (RarFileNameComparer.IsRarFile(inFile.Name))
            {
                fs = new RarStream(inFile.FullName);
            }
            else
            {
                fs = inFile.OpenRead();
            }

            using (EbmlReader rdr = new EbmlReader(fs, EbmlReadMode.MKV))
            {
                long startOffset = long.MaxValue;
                foreach (TrackData track in tracks.Values)
                {
                    if (track.MatchOffset > 0)
                    {
                        startOffset = Math.Min(track.MatchOffset, startOffset);
                    }
                }

                string currentAttachment = null;
                int    clustercount      = 0;
                bool   done = false;
                while (rdr.Read() && !done)
                {
                    switch (rdr.ElementType)
                    {
                    case EbmlElementType.Segment:
                    case EbmlElementType.AttachmentList:
                    case EbmlElementType.Attachment:
                    case EbmlElementType.BlockGroup:
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.Cluster:
                        // simple progress indicator since this can take a while (cluster is good because they're about 1mb each)
                        Console.Write("\b{0}", Program.spinners[clustercount++ % Program.spinners.Length]);

                        // in extract mode, we know the first data offset we're looking for, so skip any clusters before that
                        if (rdr.Element.ElementStartPos + rdr.Element.RawHeader.Length + rdr.Element.Length < startOffset)
                        {
                            rdr.SkipContents();
                        }
                        else
                        {
                            rdr.MoveToChild();
                        }
                        break;

                    case EbmlElementType.AttachedFileName:
                        currentAttachment = Encoding.UTF8.GetString(rdr.ReadContents());
                        if (!attachments.ContainsKey(currentAttachment))
                        {
                            attachments.Add(currentAttachment, new AttachmentData()
                            {
                                Name = currentAttachment
                            });
                        }
                        break;

                    case EbmlElementType.AttachedFileData:
                        AttachmentData attachment = attachments[currentAttachment];
                        attachment.Size = rdr.Element.Length;

                        // in extract mode, extract all attachments in case we need them later
                        if (attachment.AttachmentFile == null)
                        {
                            attachment.AttachmentFile = new FileStream(Path.Combine(outDir.FullName, attachment.Name), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x10000, FileOptions.DeleteOnClose);
                        }

                        byte[] buff = rdr.ReadContents();
                        attachment.AttachmentFile.Write(buff, 0, buff.Length);
                        attachment.AttachmentFile.Seek(0, SeekOrigin.Begin);
                        break;

                    case EbmlElementType.Block:
                        TrackData track = tracks[rdr.Block.TrackNumber];

                        if (rdr.Block.ElementStartPos + rdr.Block.RawHeader.Length + rdr.Block.RawBlockHeader.Length + rdr.Block.Length > track.MatchOffset)
                        {
                            if (track.TrackFile == null)
                            {
                                track.TrackFile = new FileStream(Path.Combine(outDir.FullName, inFile.Name + "." + track.TrackNumber.ToString("d3")), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x10000, FileOptions.DeleteOnClose);
                            }

                            buff = rdr.ReadContents();
                            int offset = 0;
                            for (int i = 0; i < rdr.Block.FrameLengths.Length; i++)
                            {
                                if (rdr.Block.ElementStartPos + rdr.Block.RawHeader.Length + rdr.Block.RawBlockHeader.Length + offset >= track.MatchOffset && track.TrackFile.Position < track.DataLength)
                                {
                                    track.TrackFile.Write(buff, offset, rdr.Block.FrameLengths[i]);
                                }

                                offset += rdr.Block.FrameLengths[i];
                            }

                            bool tracksDone = true;
                            foreach (TrackData t in tracks.Values)
                            {
                                if (t.TrackFile == null || t.TrackFile.Length < t.DataLength)
                                {
                                    tracksDone = false;
                                    break;
                                }
                            }
                            done = tracksDone;
                        }
                        else
                        {
                            rdr.SkipContents();
                        }
                        break;

                    default:
                        rdr.SkipContents();
                        break;
                    }
                }
            }

            Console.Write('\b');
        }
예제 #5
0
        public static void FindSampleStreams(SortedList <int, TrackData> tracks, FileInfo inFile)
        {
            Stream fs;

            if (RarFileNameComparer.IsRarFile(inFile.Name))
            {
                fs = new RarStream(inFile.FullName);
            }
            else
            {
                fs = inFile.OpenRead();
            }

            using (EbmlReader rdr = new EbmlReader(fs, EbmlReadMode.MKV))
            {
                int  clustercount = 0;
                bool done         = false;
                while (rdr.Read() && !done)
                {
                    switch (rdr.ElementType)
                    {
                    case EbmlElementType.Segment:
                    case EbmlElementType.BlockGroup:
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.Cluster:
                        // simple progress indicator since this can take a while (cluster is good because they're about 1mb each)
                        Console.Write("\b{0}", Program.spinners[clustercount++ % Program.spinners.Length]);
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.Block:
                        if (!tracks.ContainsKey(rdr.Block.TrackNumber))
                        {
                            tracks.Add(rdr.Block.TrackNumber, new TrackData()
                            {
                                TrackNumber = (ushort)rdr.Block.TrackNumber
                            });
                        }

                        TrackData track = tracks[rdr.Block.TrackNumber];

                        // it's possible the sample didn't require or contain data for all tracks in the main file
                        //  if that happens, we obviously don't want to try to match the data
                        if (track.SignatureBytes != null && (track.MatchOffset == 0 || track.CheckBytes.Length < track.SignatureBytes.Length))
                        {
                            // here, the data we're looking for might not start in the first frame (lace) of the block, so we need to check them all
                            byte[] buff   = rdr.ReadContents();
                            int    offset = 0;
                            for (int i = 0; i < rdr.Block.FrameLengths.Length; i++)
                            {
                                if (track.CheckBytes != null && track.CheckBytes.Length < track.SignatureBytes.Length)
                                {
                                    byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, rdr.Block.FrameLengths[i] + track.CheckBytes.Length)];
                                    Buffer.BlockCopy(track.CheckBytes, 0, checkBytes, 0, track.CheckBytes.Length);
                                    Buffer.BlockCopy(buff, offset, checkBytes, track.CheckBytes.Length, checkBytes.Length - track.CheckBytes.Length);

                                    if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length))
                                    {
                                        track.CheckBytes = checkBytes;
                                    }
                                    else
                                    {
                                        // it was only a partial match.  start over
                                        track.CheckBytes  = null;
                                        track.MatchOffset = 0;
                                        track.MatchLength = 0;
                                    }
                                }

                                // this is a bit weird, but if we had a false positive match going and discovered it above, we check this frame again
                                //  to see if it's the start of a new match (rare problem, but it can happen with subtitles especially)
                                if (track.CheckBytes == null)
                                {
                                    byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, rdr.Block.FrameLengths[i])];
                                    Buffer.BlockCopy(buff, offset, checkBytes, 0, checkBytes.Length);

                                    if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length))
                                    {
                                        track.CheckBytes  = checkBytes;
                                        track.MatchOffset = rdr.Block.ElementStartPos + rdr.Block.RawHeader.Length + rdr.Block.RawBlockHeader.Length + offset;
                                        track.MatchLength = Math.Min(track.DataLength, rdr.Block.FrameLengths[i]);
                                    }
                                }
                                else
                                {
                                    track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.Block.FrameLengths[i]);
                                }

                                offset += rdr.Block.FrameLengths[i];
                            }
                        }
                        else if (track.MatchLength < track.DataLength)
                        {
                            track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.Element.Length);
                            rdr.SkipContents();

                            bool tracksDone = true;
                            foreach (TrackData t in tracks.Values)
                            {
                                if (t.MatchLength < t.DataLength)
                                {
                                    tracksDone = false;
                                    break;
                                }
                            }
                            done = tracksDone;
                        }
                        else
                        {
                            rdr.SkipContents();
                        }
                        break;

                    default:
                        rdr.SkipContents();
                        break;
                    }
                }
            }

            Console.Write('\b');
        }
예제 #6
0
        public static int ProfileSample(FileData file, SortedList <int, TrackData> tracks, Dictionary <string, AttachmentData> attachments)
        {
            long   otherLength       = 0;
            int    clustercount      = 0;
            int    blockcount        = 0;
            string currentAttachment = null;

            byte[] elmContent = null;

            file.Crc32 = Crc32.StartValue;
            using (EbmlReader rdr = new EbmlReader(file.Name, EbmlReadMode.Sample))
            {
                while (rdr.Read())
                {
                    otherLength += rdr.Element.RawHeader.Length;
                    file.Crc32   = Crc32.GetCrc(file.Crc32, rdr.Element.RawHeader);

                    switch (rdr.ElementType)
                    {
                    case EbmlElementType.Segment:
                        // segment should be the first thing following the header.  this is a good time to do a check for file size.
                        if (rdr.Element.ElementStartPos + rdr.Element.RawHeader.Length + rdr.Element.Length != file.Size)
                        {
                            Program.ReportError(string.Format("\nWarning: File size does not appear to be correct!\n\t Expected: {0:n0}\n\t Found   : {1:n0}\n", rdr.Element.ElementStartPos + rdr.Element.RawHeader.Length + rdr.Element.Length, file.Size));
                        }
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.Cluster:
                        // simple progress indicator since this can take a while (cluster is good because they're about 1mb each)
                        Console.Write("\b{0}", Program.spinners[clustercount++ % Program.spinners.Length]);
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.BlockGroup:
                    case EbmlElementType.AttachmentList:
                    case EbmlElementType.Attachment:
                        // these elements have no useful info of their own, but we want to step into them to examine their children
                        rdr.MoveToChild();
                        break;

                    case EbmlElementType.AttachedFileName:
                        elmContent        = rdr.ReadContents();
                        otherLength      += elmContent.Length;
                        file.Crc32        = Crc32.GetCrc(file.Crc32, elmContent);
                        currentAttachment = Encoding.UTF8.GetString(elmContent);
                        if (!attachments.ContainsKey(currentAttachment))
                        {
                            attachments.Add(currentAttachment, new AttachmentData()
                            {
                                Name = currentAttachment
                            });
                        }
                        break;

                    case EbmlElementType.AttachedFileData:
                        elmContent = rdr.ReadContents();
                        attachments[currentAttachment].Size = elmContent.Length;
                        file.Crc32 = Crc32.GetCrc(file.Crc32, elmContent);
                        break;

                    case EbmlElementType.Block:
                        blockcount++;
                        if (!tracks.ContainsKey(rdr.Block.TrackNumber))
                        {
                            tracks.Add(rdr.Block.TrackNumber, new TrackData()
                            {
                                TrackNumber = (ushort)rdr.Block.TrackNumber
                            });
                        }

                        TrackData track = tracks[rdr.Block.TrackNumber];
                        track.DataLength += rdr.Block.Length;

                        otherLength += rdr.Block.RawBlockHeader.Length;
                        file.Crc32   = Crc32.GetCrc(file.Crc32, rdr.Block.RawBlockHeader);

                        elmContent = rdr.ReadContents();
                        file.Crc32 = Crc32.GetCrc(file.Crc32, elmContent);

                        // in profile mode, we want to build track signatures
                        if (track.SignatureBytes == null || track.SignatureBytes.Length < Program.sigSize)
                        {
                            // here, we can completely ignore laces, because we know what we're looking for always starts at the beginning
                            if (track.SignatureBytes != null)
                            {
                                byte[] sig = new byte[Math.Min(Program.sigSize, track.SignatureBytes.Length + elmContent.Length)];
                                Buffer.BlockCopy(track.SignatureBytes, 0, sig, 0, track.SignatureBytes.Length);
                                Buffer.BlockCopy(elmContent, 0, sig, track.SignatureBytes.Length, sig.Length - track.SignatureBytes.Length);
                                track.SignatureBytes = sig;
                            }
                            else
                            {
                                track.SignatureBytes = new byte[Math.Min(Program.sigSize, elmContent.Length)];
                                Buffer.BlockCopy(elmContent, 0, track.SignatureBytes, 0, track.SignatureBytes.Length);
                            }
                        }
                        break;

                    default:
                        otherLength += rdr.Element.Length;
                        file.Crc32   = Crc32.GetCrc(file.Crc32, rdr.ReadContents());
                        break;
                    }
                }
            }
            Console.Write("\b");

            file.Crc32 = ~file.Crc32;

            long totalSize      = otherLength;
            long attachmentSize = 0;

            Console.WriteLine("File Details:   Size           CRC");
            Console.WriteLine("                -------------  --------");
            Console.WriteLine("                {0,13:n0}  {1:X8}\n", file.Size, file.Crc32);

            if (attachments.Count > 0)
            {
                Console.WriteLine("Attachments:    File Name                  Size");
                Console.WriteLine("                -------------------------  ------------");
                foreach (AttachmentData attachment in attachments.Values)
                {
                    Console.WriteLine("                {0,-25}  {1,12:n0}", attachment.Name.Substring(0, Math.Min(25, attachment.Name.Length)), attachment.Size);
                    totalSize      += attachment.Size;
                    attachmentSize += attachment.Size;
                }
            }

            Console.WriteLine();
            Console.WriteLine("Track Details:  Track  Length");
            Console.WriteLine("                -----  -------------");
            foreach (TrackData track in tracks.Values)
            {
                Console.WriteLine("                {0,5:n0}  {1,13:n0}", track.TrackNumber, track.DataLength);
                totalSize += track.DataLength;
            }

            Console.WriteLine();
            Console.WriteLine("Parse Details:  Metadata     Attachments   Track Data     Total");
            Console.WriteLine("                -----------  ------------  -------------  -------------");
            Console.WriteLine("                {0,11:n0}  {1,12:n0}  {2,13:n0}  {3,13:n0}\n", otherLength, attachmentSize, totalSize - attachmentSize - otherLength, totalSize);

            if (file.Size != totalSize)
            {
                Program.ReportError("\nError: Parsed size does not equal file size.\n       The sample is likely corrupted or incomplete.\n");
                return(2);
            }

            return(0);
        }
예제 #7
0
        public static FileData RebuildSample(FileData file, SortedList <int, TrackData> tracks, FileInfo srsFile, DirectoryInfo outDir)
        {
            uint crc = Crc32.StartValue;

            using (RiffReader rdr = new RiffReader(srsFile.FullName, RiffReadMode.SRS))
                using (FileStream fsOut = new FileStream(Path.Combine(outDir.FullName, file.Name), FileMode.Create))
                {
                    int blockcount = 0;
                    while (rdr.Read())
                    {
                        // skip over our custom chunks in rebuild mode (only read it in load mode)
                        if (rdr.Chunk.FourCC == "SRSF" || rdr.Chunk.FourCC == "SRST")
                        {
                            rdr.SkipContents();
                            continue;
                        }

                        fsOut.Write(rdr.Chunk.RawHeader, 0, rdr.Chunk.RawHeader.Length);
                        crc = Crc32.GetCrc(crc, rdr.Chunk.RawHeader);

                        if (rdr.ChunkType == RiffChunkType.List)
                        {
                            rdr.MoveToChild();
                        }
                        else
                        {
                            if (rdr.ChunkType == RiffChunkType.Movi)
                            {
                                if (++blockcount % 15 == 0)
                                {
                                    Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]);
                                }

                                TrackData track = tracks[rdr.MoviChunk.StreamNumber];
                                byte[]    buff  = new byte[rdr.MoviChunk.Length];
                                track.TrackFile.Read(buff, 0, buff.Length);
                                fsOut.Write(buff, 0, buff.Length);
                                crc = Crc32.GetCrc(crc, buff);
                                rdr.SkipContents();
                            }
                            else
                            {
                                byte[] buff = rdr.ReadContents();
                                fsOut.Write(buff, 0, buff.Length);
                                crc = Crc32.GetCrc(crc, buff);
                            }

                            if (rdr.HasPad)
                            {
                                fsOut.WriteByte(rdr.PadByte);
                                crc = Crc32.GetCrc(crc, new byte[] { rdr.PadByte });
                            }
                        }
                    }
                }
            Console.Write('\b');

            FileData newFile = new FileData(Path.Combine(outDir.FullName, file.Name));

            newFile.Crc32 = ~crc;

            return(newFile);
        }
예제 #8
0
        public static void ExtractSampleStreams(SortedList <int, TrackData> tracks, FileData file, FileInfo inFile, DirectoryInfo outDir)
        {
            Stream fs;

            if (RarFileNameComparer.IsRarFile(inFile.Name))
            {
                fs = new RarStream(inFile.FullName);
            }
            else
            {
                fs = inFile.OpenRead();
            }

            using (RiffReader rdr = new RiffReader(fs, RiffReadMode.AVI))
            {
                long startOffset = long.MaxValue;
                foreach (TrackData track in tracks.Values)
                {
                    if (track.MatchOffset > 0)
                    {
                        startOffset = Math.Min(track.MatchOffset, startOffset);
                    }
                }

                int  blockcount = 0;
                bool done       = false;
                while (rdr.Read() && !done)
                {
                    if (rdr.ChunkType == RiffChunkType.List)
                    {
                        rdr.MoveToChild();
                    }
                    else                     // normal chunk
                    {
                        if (rdr.ChunkType == RiffChunkType.Movi)
                        {
                            if (++blockcount % 15 == 0)
                            {
                                Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]);
                            }

                            if (!tracks.ContainsKey(rdr.MoviChunk.StreamNumber))
                            {
                                tracks.Add(rdr.MoviChunk.StreamNumber, new TrackData());
                            }

                            TrackData track = tracks[rdr.MoviChunk.StreamNumber];

                            if (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length + rdr.MoviChunk.Length > track.MatchOffset)
                            {
                                if (track.TrackFile == null)
                                {
                                    track.TrackFile = new FileStream(Path.Combine(outDir.FullName, inFile.Name + "." + track.TrackNumber.ToString("d3")), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x10000, FileOptions.DeleteOnClose);
                                }

                                if (track.TrackFile.Position < track.DataLength)
                                {
                                    if (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length >= track.MatchOffset)
                                    {
                                        track.TrackFile.Write(rdr.ReadContents(), 0, (int)rdr.MoviChunk.Length);
                                    }
                                    else
                                    {
                                        int chunkOffset = (int)(track.MatchOffset - (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length));
                                        track.TrackFile.Write(rdr.ReadContents(), chunkOffset, (int)rdr.MoviChunk.Length - chunkOffset);
                                    }
                                }

                                bool tracksDone = true;
                                foreach (TrackData t in tracks.Values)
                                {
                                    if (t.TrackFile == null || t.TrackFile.Length < t.DataLength)
                                    {
                                        tracksDone = false;
                                        break;
                                    }
                                }
                                done = tracksDone;
                            }

                            rdr.SkipContents();
                        }
                        else
                        {
                            rdr.SkipContents();
                        }
                    }
                }
            }

            Console.Write('\b');
        }
예제 #9
0
        public static void FindSampleStreams(SortedList <int, TrackData> tracks, FileInfo inFile)
        {
            Stream fs;

            if (RarFileNameComparer.IsRarFile(inFile.Name))
            {
                fs = new RarStream(inFile.FullName);
            }
            else
            {
                fs = inFile.OpenRead();
            }

            using (RiffReader rdr = new RiffReader(fs, RiffReadMode.AVI))
            {
                int  blockcount = 0;
                bool done       = false;
                while (rdr.Read() && !done)
                {
                    if (rdr.ChunkType == RiffChunkType.List)
                    {
                        rdr.MoveToChild();
                    }
                    else                     // normal chunk
                    {
                        if (rdr.ChunkType == RiffChunkType.Movi)
                        {
                            if (++blockcount % 15 == 0)
                            {
                                Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]);
                            }

                            int trackno = rdr.MoviChunk.StreamNumber;
                            if (!tracks.ContainsKey(trackno))
                            {
                                tracks.Add(trackno, new TrackData());
                            }

                            TrackData track = tracks[trackno];
                            track.TrackNumber = (byte)trackno;

                            if (track.MatchOffset == 0 || track.CheckBytes.Length < track.SignatureBytes.Length)
                            {
                                // it's possible the sample didn't require or contain data for all tracks in the main file
                                //  if that happens, we obviously don't want to try to match the data
                                if (track.SignatureBytes != null)
                                {
                                    if (track.CheckBytes != null && track.CheckBytes.Length < track.SignatureBytes.Length)
                                    {
                                        byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, rdr.MoviChunk.Length + track.CheckBytes.Length)];
                                        track.CheckBytes.CopyTo(checkBytes, 0);
                                        Buffer.BlockCopy(rdr.ReadContents(), 0, checkBytes, track.CheckBytes.Length, checkBytes.Length - track.CheckBytes.Length);

                                        if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length))
                                        {
                                            track.CheckBytes = checkBytes;
                                        }
                                        else
                                        {
                                            // it was only a partial match.  start over
                                            track.CheckBytes  = null;
                                            track.MatchOffset = 0;
                                            track.MatchLength = 0;
                                        }
                                    }

                                    // this is a bit weird, but if we had a false positive match going and discovered it above, we check this frame again
                                    //  to see if it's the start of a new match (probably will never happen with AVI, but it does in MKV, so just in case...)
                                    if (track.CheckBytes == null)
                                    {
                                        byte[] chunkBytes = rdr.ReadContents();

                                        byte searchByte = track.SignatureBytes[0];
                                        int  foundPos   = -1;
                                        while ((foundPos = Array.IndexOf <byte>(chunkBytes, searchByte, foundPos + 1)) > -1)
                                        {
                                            byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, chunkBytes.Length - foundPos)];
                                            Buffer.BlockCopy(chunkBytes, foundPos, checkBytes, 0, checkBytes.Length);

                                            if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length))
                                            {
                                                track.CheckBytes  = checkBytes;
                                                track.MatchOffset = rdr.Chunk.ChunkStartPos + rdr.Chunk.RawHeader.Length + foundPos;
                                                track.MatchLength = Math.Min(track.DataLength, chunkBytes.Length - foundPos);
                                                break;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.MoviChunk.Length);
                                    }
                                }
                            }
                            else if (track.MatchLength < track.DataLength)
                            {
                                track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.MoviChunk.Length);

                                bool tracksDone = true;
                                foreach (TrackData t in tracks.Values)
                                {
                                    if (t.MatchLength < t.DataLength)
                                    {
                                        tracksDone = false;
                                        break;
                                    }
                                }
                                done = tracksDone;
                            }

                            rdr.SkipContents();
                        }
                        else
                        {
                            rdr.SkipContents();
                        }
                    }
                }
            }

            Console.Write('\b');
        }
예제 #10
0
        public static int ProfileSample(FileData file, SortedList <int, TrackData> tracks)
        {
            long otherLength = 0;
            int  blockcount  = 0;

            file.Crc32 = Crc32.StartValue;
            using (RiffReader rdr = new RiffReader(file.Name, RiffReadMode.Sample))
            {
                while (rdr.Read())
                {
                    otherLength += rdr.Chunk.RawHeader.Length;
                    file.Crc32   = Crc32.GetCrc(file.Crc32, rdr.Chunk.RawHeader);

                    if (rdr.ChunkType == RiffChunkType.List)
                    {
                        if (rdr.List.ListType == "RIFF" && rdr.List.ChunkStartPos + rdr.List.RawHeader.Length + rdr.List.Length > file.Size)
                        {
                            Program.ReportError(string.Format("\nWarning: File size does not appear to be correct!\n\t Expected at least: {0:n0}\n\t Found            : {1:n0}\n", rdr.List.ChunkStartPos + rdr.List.RawHeader.Length + rdr.List.Length, file.Size));
                        }

                        rdr.MoveToChild();
                    }
                    else                                         // normal chunk
                    {
                        if (rdr.ChunkType == RiffChunkType.Movi) // chunk containing stream data (our main focus)
                        {
                            if (++blockcount % 15 == 0)
                            {
                                Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]);
                            }

                            int trackno = rdr.MoviChunk.StreamNumber;
                            if (!tracks.ContainsKey(trackno))
                            {
                                tracks.Add(trackno, new TrackData());
                            }

                            TrackData track = tracks[trackno];
                            track.TrackNumber = (byte)trackno;
                            track.DataLength += rdr.MoviChunk.Length;

                            byte[] moviData = rdr.ReadContents();
                            file.Crc32 = Crc32.GetCrc(file.Crc32, moviData);

                            // in profile mode, we want to build track signatures
                            if (track.SignatureBytes == null || track.SignatureBytes.Length < Program.sigSize)
                            {
                                if (track.SignatureBytes != null)
                                {
                                    byte[] sig = new byte[Math.Min(Program.sigSize, track.SignatureBytes.Length + rdr.MoviChunk.Length)];
                                    track.SignatureBytes.CopyTo(sig, 0);
                                    Buffer.BlockCopy(moviData, 0, sig, track.SignatureBytes.Length, sig.Length - track.SignatureBytes.Length);
                                    track.SignatureBytes = sig;
                                }
                                else
                                {
                                    track.SignatureBytes = new byte[Math.Min(Program.sigSize, rdr.MoviChunk.Length)];
                                    Buffer.BlockCopy(moviData, 0, track.SignatureBytes, 0, track.SignatureBytes.Length);
                                }
                            }
                        }
                        else
                        {
                            otherLength += rdr.Chunk.Length;
                            file.Crc32   = Crc32.GetCrc(file.Crc32, rdr.ReadContents());
                        }

                        if (rdr.HasPad)
                        {
                            otherLength++;
                            file.Crc32 = Crc32.GetCrc(file.Crc32, new byte[] { rdr.PadByte });
                        }
                    }
                }
            }

            Console.Write('\b');

            file.Crc32 = ~file.Crc32;
            long totalSize = otherLength;

            Console.WriteLine("File Details:   Size           CRC");
            Console.WriteLine("                -------------  --------");
            Console.WriteLine("                {0,13:n0}  {1:X8}\n", file.Size, file.Crc32);

            Console.WriteLine();
            Console.WriteLine("Stream Details:  Stream  Length");
            Console.WriteLine("                 ------  -------------");
            foreach (TrackData track in tracks.Values)
            {
                Console.WriteLine("                 {0,6:n0}  {1,13:n0}", track.TrackNumber, track.DataLength);
                totalSize += track.DataLength;
            }

            Console.WriteLine();
            Console.WriteLine("Parse Details:   Metadata     Stream Data    Total");
            Console.WriteLine("                 -----------  -------------  -------------");
            Console.WriteLine("                 {0,11:n0}  {1,13:n0}  {2,13:n0}\n", otherLength, totalSize - otherLength, totalSize);

            if (file.Size != totalSize)
            {
                Program.ReportError("\nError: Parsed size does not equal file size.\n       The sample is likely corrupted or incomplete.\n");
                return(2);
            }

            return(0);
        }