Beispiel #1
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);
        }
Beispiel #2
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');
        }