예제 #1
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');
        }
예제 #2
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');
        }
예제 #3
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');
        }
예제 #4
0
파일: srr.cs 프로젝트: zc0nf/pyrescene
        static int CreateReconstructionFile(List <FileInfo> inFiles, DirectoryInfo inFolder, List <string> storeFiles, string srrName, bool savePaths)
        {
            using (FileStream srrfs = new FileStream(srrName, FileMode.Create))
            {
                BinaryWriter bw = new BinaryWriter(srrfs, Encoding.ASCII);
                bw.Write(new SrrHeaderBlock(appName).RawData);

                // we store copies of any files included in the storeFiles list in the .srr using a "store block".  any SFV files used are also included.
                foreach (FileInfo fi in inFiles)
                {
                    if (fi.Extension.ToLower() == ".sfv")
                    {
                        storeFiles.Add(fi.FullName);
                    }
                }

                SrrStoredFileBlock storeBlock = null;
                foreach (string fileName in storeFiles)
                {
                    string searchName = fileName;
                    if (!Path.IsPathRooted(searchName))
                    {
                        searchName = Path.Combine(inFolder.FullName, fileName);
                    }

                    DirectoryInfo searchDir = new DirectoryInfo(Path.GetDirectoryName(searchName));
                    if (searchDir.Exists)
                    {
                        foreach (FileInfo storeFile in searchDir.GetFiles(Path.GetFileName(searchName)))
                        {
                            string fName = savePaths ? MakePathRelative(storeFile.FullName, inFolder.FullName) : storeFile.Name;
                            Console.WriteLine("Storing file: {0}", fName);
                            storeBlock = new SrrStoredFileBlock(fName, (int)storeFile.Length);
                            if (savePaths)
                            {
                                storeBlock.Flags |= (ushort)SrrStoredFileBlock.FlagValues.PathsSaved;
                            }
                            using (FileStream storefs = storeFile.OpenRead())
                                storefs.Read(storeBlock.RawData, storeBlock.FileOffset, (int)storeFile.Length);

                            bw.Write(storeBlock.RawData);
                        }
                    }
                }

                List <string> rarFiles = new List <string>();
                foreach (FileInfo inFile in inFiles)
                {
                    if (inFile.Extension.ToLower() == ".sfv")
                    {
                        using (SfvReader sfvReader = new SfvReader(inFile.FullName))
                        {
                            List <string> sfvRarFiles = new List <string>();
                            SfvEntry      sfvEntry;
                            while ((sfvEntry = sfvReader.Read()) != null)
                            {
                                if (RarFileNameComparer.IsRarFile(sfvEntry.FileName))
                                {
                                    sfvRarFiles.Add(Path.Combine(inFile.DirectoryName, sfvEntry.FileName));
                                }
                                else
                                {
                                    ReportError(string.Format("Warning: Non-RAR file referenced in SFV: {0}\n\tThis file cannot be recreated unless it is stored using -s", sfvEntry.FileName));
                                    continue;
                                }
                            }

                            sfvRarFiles.Sort(new RarFileNameComparer());
                            rarFiles.AddRange(sfvRarFiles);
                        }
                    }
                    else
                    {
                        bool     oldNameFormat = false;
                        RarBlock block         = null;
                        using (RarReader rdr = new RarReader(inFile.FullName, RarReadMode.RAR))
                            while ((block = rdr.Read()) != null)
                            {
                                if (block is RarVolumeHeaderBlock && ((block.Flags & (ushort)RarVolumeHeaderBlock.FlagValues.Volume) != 0))
                                {
                                    if ((block.Flags & (ushort)RarVolumeHeaderBlock.FlagValues.FirstVolume) == 0)
                                    {
                                        throw new InvalidDataException("You must start with the first volume from a RAR set");
                                    }

                                    oldNameFormat = (block.Flags & (ushort)RarVolumeHeaderBlock.FlagValues.NewNumbering) == 0;
                                }
                            }

                        string nextFileName = inFile.FullName;
                        while (File.Exists(nextFileName))
                        {
                            rarFiles.Add(Path.Combine(inFile.DirectoryName, nextFileName));
                            nextFileName = RarFileNameFinder.FindNextFileName(nextFileName, oldNameFormat);
                        }
                    }
                }

                foreach (string fileName in rarFiles)
                {
                    if (!File.Exists(fileName))
                    {
                        ReportError(string.Format("Referenced file not found: {0}", fileName));
                        srrfs.Close();
                        File.Delete(srrName);
                        return(2);
                    }

                    string fName = savePaths ? MakePathRelative(fileName, inFolder.FullName) : Path.GetFileName(fileName);
                    Console.WriteLine("Processing file: {0}", fName);

                    SrrRarFileBlock rarBlock = new SrrRarFileBlock(fName);
                    if (savePaths)
                    {
                        rarBlock.Flags |= (ushort)SrrRarFileBlock.FlagValues.PathsSaved;
                    }

                    bw.Write(rarBlock.RawData);
                    using (RarReader rarReader = new RarReader(fileName, RarReadMode.RAR))
                    {
                        RarBlock block;
                        while ((block = rarReader.Read()) != null)
                        {
                            if (verbose)
                            {
                                Console.WriteLine("\tBlock Type: 0x{0:x2}", block.RawType);
                                Console.WriteLine("\tBlock Size: {0}", block.RawData.Length);
                            }

                            if (block is RarPackedFileBlock)
                            {
                                RarPackedFileBlock fileData = (RarPackedFileBlock)block;

                                if (verbose)
                                {
                                    Console.WriteLine("\t\tCompression Type: 0x{0:x2}", fileData.CompressionMethod);
                                    Console.WriteLine("\t\tPacked Data Size: {0:n0}", fileData.PackedSize);
                                    Console.WriteLine("\t\tFile Size: {0:n0}", fileData.UnpackedSize);
                                    Console.WriteLine("\t\tFile Name: {0}", fileData.FileName);
                                }

                                if (fileData.CompressionMethod != 0x30)
                                {
                                    ReportError(string.Format("Archive uses unsupported compression method: {0}", fileName));
                                    srrfs.Close();
                                    File.Delete(srrName);
                                    return(3);
                                }
                            }
                            else if (block is RarRecoveryBlock)
                            {
                                RarRecoveryBlock subData = (RarRecoveryBlock)block;

                                if (verbose & subData.RecoverySectors > 0)
                                {
                                    Console.WriteLine("\t\tRecovery Record Size: {0:n0}", subData.PackedSize);
                                    Console.WriteLine("\t\tRecovery Sectors: {0:n0}", subData.RecoverySectors);
                                    Console.WriteLine("\t\tProtected Sectors: {0:n0}", subData.DataSectors);
                                }
                            }

                            // store the raw data for any blocks found
                            bw.Write(block.RawData);
                        }
                    }
                }
            }

            Console.WriteLine("\nReconstruction file successfully created: {0}", srrName);

            return(0);
        }
예제 #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 (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');
        }