예제 #1
0
        public void Tar_VeryLongFilepathReadback()
        {
            string archive = "Tar_VeryLongFilepathReadback.tar";


            // create a very long filename
            string longFilename = "";

            for (int i = 0; i < 600; i = longFilename.Length)
            {
                longFilename += i.ToString("D10") + "-";
            }
            longFilename += ".txt";

            // Step 1: create a tar file containing a file with a long name
            using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
                using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
                    using (Stream inputStream = new MemoryStream())
                    {
                        StreamWriter sw = new StreamWriter(inputStream);
                        sw.Write("dummy filecontent");
                        sw.Flush();

                        inputStream.Position = 0;
                        writer.Write(longFilename, inputStream, null);
                    }

            // Step 2: check if the written tar file can be read correctly
            string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive);

            using (var archive2 = TarArchive.Open(unmodified))
            {
                Assert.Equal(1, archive2.Entries.Count);
                Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key));

                foreach (var entry in archive2.Entries)
                {
                    Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine());
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Constructor with a FileInfo object to an existing file.
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <param name="options"></param>
        public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
        {
            fileInfo.CheckNotNull(nameof(fileInfo));
            if (options == null)
            {
                options = new ReaderOptions {
                    LeaveStreamOpen = false
                }
            }
            ;

            ArchiveType?type;

            using (Stream stream = fileInfo.OpenRead())
            {
                IsArchive(stream, out type); //test and reset stream position

                if (type != null)
                {
                    switch (type.Value)
                    {
                    case ArchiveType.Zip:
                        return(ZipArchive.Open(fileInfo, options));

                    case ArchiveType.SevenZip:
                        return(SevenZipArchive.Open(fileInfo, options));

                    case ArchiveType.GZip:
                        return(GZipArchive.Open(fileInfo, options));

                    case ArchiveType.Rar:
                        return(RarArchive.Open(fileInfo, options));

                    case ArchiveType.Tar:
                        return(TarArchive.Open(fileInfo, options));
                    }
                }
            }
            throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
        }
예제 #3
0
        /// <summary>
        /// Opens an Archive for random access
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static IArchive Open(Stream stream, Options options)
        {
            //stream.CheckNotNull("stream");
            Utility.CheckNotNull(stream, "stream");
            if (!stream.CanRead || !stream.CanSeek)
            {
                throw new ArgumentException("Stream should be readable and seekable");
            }

            if (ZipArchive.IsZipFile(stream, null))
            {
                stream.Seek(0, SeekOrigin.Begin);
                return(ZipArchive.Open(stream, options, null));
            }
            stream.Seek(0, SeekOrigin.Begin);
            if (TarArchive.IsTarFile(stream))
            {
                stream.Seek(0, SeekOrigin.Begin);
                return(TarArchive.Open(stream, options));
            }
            stream.Seek(0, SeekOrigin.Begin);
            if (SevenZipArchive.IsSevenZipFile(stream))
            {
                stream.Seek(0, SeekOrigin.Begin);
                return(SevenZipArchive.Open(stream, options));
            }
            stream.Seek(0, SeekOrigin.Begin);
            if (GZipArchive.IsGZipFile(stream))
            {
                stream.Seek(0, SeekOrigin.Begin);
                return(GZipArchive.Open(stream, options));
            }
            stream.Seek(0, SeekOrigin.Begin);
            if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
            {
                stream.Seek(0, SeekOrigin.Begin);
                return(RarArchive.Open(stream, options));
            }
            throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
        }
예제 #4
0
        private IArchive GetArchiveReader(CompressionType romFileCompressionType, string sourceFile)
        {
            switch (romFileCompressionType)
            {
            case CompressionType.Sevenzip:
                return(SevenZipArchive.Open(sourceFile));

            case CompressionType.Gzip:
                return(GZipArchive.Open(sourceFile));

            case CompressionType.Rar:
                return(RarArchive.Open(sourceFile));

            case CompressionType.Tar:
                return(TarArchive.Open(sourceFile));

            case CompressionType.Zip:
                return(ZipArchive.Open(sourceFile));
            }

            return(null);
        }
예제 #5
0
        /// <summary>
        /// Constructor with a FileInfo object to an existing file.
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <param name="options"></param>
        public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
        {
            fileInfo.CheckNotNull("fileInfo");
            options = options ?? new ReaderOptions();

            using (var stream = fileInfo.OpenRead())
            {
                if (ZipArchive.IsZipFile(stream, null))
                {
                    stream.Dispose();
                    return(ZipArchive.Open(fileInfo, options));
                }
                stream.Seek(0, SeekOrigin.Begin);
                if (SevenZipArchive.IsSevenZipFile(stream))
                {
                    stream.Dispose();
                    return(SevenZipArchive.Open(fileInfo, options));
                }
                stream.Seek(0, SeekOrigin.Begin);
                if (GZipArchive.IsGZipFile(stream))
                {
                    stream.Dispose();
                    return(GZipArchive.Open(fileInfo, options));
                }
                stream.Seek(0, SeekOrigin.Begin);
                if (RarArchive.IsRarFile(stream, options))
                {
                    stream.Dispose();
                    return(RarArchive.Open(fileInfo, options));
                }
                stream.Seek(0, SeekOrigin.Begin);
                if (TarArchive.IsTarFile(stream))
                {
                    stream.Dispose();
                    return(TarArchive.Open(fileInfo, options));
                }
                throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
            }
        }
        public async Task <GetImagesFromArchiveResult> GetImagesFromTarFileAsync(StorageFile file)
        {
            CompositeDisposable disposables = new CompositeDisposable();
            var stream = await file.OpenStreamForReadAsync()
                         .AddTo(disposables);

            var zipArchive = TarArchive.Open(stream)
                             .AddTo(disposables);

            var supportedEntries = zipArchive.Entries
                                   .OrderBy(x => x.Key)
                                   .Where(x => SupportedFileTypesHelper.IsSupportedImageFileExtension(x.Key))
                                   .Select(x => (IImageSource) new ArchiveEntryImageSource(x, file, _recyclableMemoryStreamManager))
                                   .ToArray();

            return new GetImagesFromArchiveResult()
                   {
                       ItemsCount = (uint)supportedEntries.Length,
                       Disposer = disposables,
                       Images = supportedEntries,
                   };
        }
예제 #7
0
 /// <summary>
 /// Opens an Archive for random access
 /// </summary>
 /// <param name="stream"></param>
 /// <param name="readerOptions"></param>
 /// <returns></returns>
 public static IArchive Open(Stream stream, ReaderOptions readerOptions = null)
 {
     stream.CheckNotNull("stream");
     if (!stream.CanRead || !stream.CanSeek)
     {
         throw new ArgumentException("Stream should be readable and seekable");
     }
     readerOptions = readerOptions ?? new ReaderOptions();
     if (ZipArchive.IsZipFile(stream, null))
     {
         stream.Seek(0, SeekOrigin.Begin);
         return(ZipArchive.Open(stream, readerOptions));
     }
     stream.Seek(0, SeekOrigin.Begin);
     if (SevenZipArchive.IsSevenZipFile(stream))
     {
         stream.Seek(0, SeekOrigin.Begin);
         return(SevenZipArchive.Open(stream, readerOptions));
     }
     stream.Seek(0, SeekOrigin.Begin);
     if (GZipArchive.IsGZipFile(stream))
     {
         stream.Seek(0, SeekOrigin.Begin);
         return(GZipArchive.Open(stream, readerOptions));
     }
     stream.Seek(0, SeekOrigin.Begin);
     if (RarArchive.IsRarFile(stream, readerOptions))
     {
         stream.Seek(0, SeekOrigin.Begin);
         return(RarArchive.Open(stream, readerOptions));
     }
     stream.Seek(0, SeekOrigin.Begin);
     if (TarArchive.IsTarFile(stream))
     {
         stream.Seek(0, SeekOrigin.Begin);
         return(TarArchive.Open(stream, readerOptions));
     }
     throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
 }
 public static bool TryOpen(FileInfo fileInfo, ReaderOptions options, ArchiveTypeMask archiveTypes, out IArchive archive)
 {
     fileInfo.CheckNotNull("fileInfo");
     options = options ?? new ReaderOptions {
         LeaveStreamOpen = false
     };
     using (var stream = fileInfo.OpenRead())
     {
         if (archiveTypes.HasFlag(ArchiveTypeMask.Zip) && ZipArchive.IsZipFile(stream, null))
         {
             archive = ZipArchive.Open(fileInfo, options);
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (archiveTypes.HasFlag(ArchiveTypeMask.SevenZip) && SevenZipArchive.IsSevenZipFile(stream))
         {
             archive = SevenZipArchive.Open(fileInfo, options);
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (archiveTypes.HasFlag(ArchiveTypeMask.GZip) && GZipArchive.IsGZipFile(stream))
         {
             archive = GZipArchive.Open(fileInfo, options);
             return(true);
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (archiveTypes.HasFlag(ArchiveTypeMask.Rar) && RarArchive.IsRarFile(stream, options))
         {
             archive = RarArchive.Open(fileInfo, options);
             return(true);
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (archiveTypes.HasFlag(ArchiveTypeMask.Tar) && TarArchive.IsTarFile(stream))
         {
             archive = TarArchive.Open(fileInfo, options);
             return(true);
         }
     }
     archive = null;
     return(false);
 }
예제 #9
0
        /// <summary>
        /// Opens an Archive for random access
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="readerOptions"></param>
        /// <returns></returns>
        public static IArchive Open(Stream stream, ReaderOptions readerOptions = null)
        {
            stream.CheckNotNull(nameof(stream));
            if (!stream.CanRead || !stream.CanSeek)
            {
                throw new ArgumentException("Stream should be readable and seekable");
            }
            if (readerOptions == null)
            {
                readerOptions = new ReaderOptions();
            }

            ArchiveType?type;

            IsArchive(stream, out type); //test and reset stream position

            if (type != null)
            {
                switch (type.Value)
                {
                case ArchiveType.Zip:
                    return(ZipArchive.Open(stream, readerOptions));

                case ArchiveType.SevenZip:
                    return(SevenZipArchive.Open(stream, readerOptions));

                case ArchiveType.GZip:
                    return(GZipArchive.Open(stream, readerOptions));

                case ArchiveType.Rar:
                    return(RarArchive.Open(stream, readerOptions));

                case ArchiveType.Tar:
                    return(TarArchive.Open(stream, readerOptions));
                }
            }
            throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
        }
예제 #10
0
        /// <summary>
        /// Attempt to extract a file as an archive
        /// </summary>
        /// <param name="outDir">Output directory for archive extraction</param>
        /// <returns>True if the extraction was a success, false otherwise</returns>
        public override bool CopyAll(string outDir)
        {
            bool encounteredErrors = true;

            try
            {
                // Create the temp directory
                Directory.CreateDirectory(outDir);

                // Extract all files to the temp directory
                TarArchive ta = TarArchive.Open(this.Filename);
                foreach (TarArchiveEntry entry in ta.Entries)
                {
                    entry.WriteToDirectory(outDir, new ExtractionOptions {
                        PreserveFileTime = true, ExtractFullPath = true, Overwrite = true
                    });
                }
                encounteredErrors = false;
                ta.Dispose();
            }
            catch (EndOfStreamException ex)
            {
                // Catch this but don't count it as an error because SharpCompress is unsafe
                logger.Verbose(ex);
            }
            catch (InvalidOperationException ex)
            {
                logger.Warning(ex);
                encounteredErrors = true;
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                encounteredErrors = true;
            }

            return(encounteredErrors);
        }
예제 #11
0
        public IArchive GetReadableArchive()
        {
            switch (Type)
            {
            case ArchiveType.Zip:
                return(ZipArchive.Open(FileInfo));

            case ArchiveType.Tar:
                return(TarArchive.Open(FileInfo));

            case ArchiveType.GZip:
                return(GZipArchive.Open(FileInfo));

            case ArchiveType.Rar:
                return(RarArchive.Open(FileInfo));

            case ArchiveType.SevenZip:
                return(SevenZipArchive.Open(FileInfo));

            default:
                throw new ArgumentOutOfRangeException(nameof(Type), Type, null);
            }
        }
예제 #12
0
        /// <summary>
        /// Constructor with a FileInfo object to an existing file.
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <param name="options"></param>
        public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
        {
            fileInfo.CheckNotNull(nameof(fileInfo));
            options = options != null ?options: new ReaderOptions {
                LeaveStreamOpen = false
            };
            using (var stream = fileInfo.OpenRead())
            {
                stream.Seek(0, SeekOrigin.Begin);
                if (GZipArchive.IsGZipFile(stream))
                {
                    return(GZipArchive.Open(fileInfo, options));
                }
                stream.Seek(0, SeekOrigin.Begin);

                stream.Seek(0, SeekOrigin.Begin);
                if (TarArchive.IsTarFile(stream))
                {
                    return(TarArchive.Open(fileInfo, options));
                }
                throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
            }
        }
예제 #13
0
 /// <summary>
 /// Constructor with a FileInfo object to an existing file.
 /// </summary>
 /// <param name="fileInfo"></param>
 /// <param name="options"></param>
 public static IArchive Open(FileInfo fileInfo, Options options)
 {
     fileInfo.CheckNotNull("fileInfo");
     using (var stream = fileInfo.OpenRead())
     {
         if (ZipArchive.IsZipFile(stream, null))
         {
             stream.Dispose();
             return(ZipArchive.Open(fileInfo, options, null));
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
         {
             stream.Dispose();
             return(RarArchive.Open(fileInfo, options));
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (TarArchive.IsTarFile(stream))
         {
             stream.Dispose();
             return(TarArchive.Open(fileInfo, options));
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (SevenZipArchive.IsSevenZipFile(stream))
         {
             stream.Dispose();
             return(SevenZipArchive.Open(fileInfo, options));
         }
         stream.Seek(0, SeekOrigin.Begin);
         if (GZipArchive.IsGZipFile(stream))
         {
             stream.Dispose();
             return(GZipArchive.Open(fileInfo, options));
         }
         throw new InvalidOperationException("Cannot determine compressed stream type.");
     }
 }
예제 #14
0
        /// <summary>
        /// Generate a list of empty folders in an archive
        /// </summary>
        /// <param name="input">Input file to get data from</param>
        /// <returns>List of empty folders in the archive</returns>
        public override List <string> GetEmptyFolders()
        {
            List <string> empties = new List <string>();

            try
            {
                TarArchive ta = TarArchive.Open(this.Filename, new ReaderOptions {
                    LeaveStreamOpen = false
                });
                List <TarArchiveEntry> tarEntries = ta.Entries.OrderBy(e => e.Key, new NaturalSort.NaturalReversedComparer()).ToList();
                string lastTarEntry = null;
                foreach (TarArchiveEntry entry in tarEntries)
                {
                    if (entry != null)
                    {
                        // If the current is a superset of last, we skip it
                        if (lastTarEntry != null && lastTarEntry.StartsWith(entry.Key))
                        {
                            // No-op
                        }
                        // If the entry is a directory, we add it
                        else if (entry.IsDirectory)
                        {
                            empties.Add(entry.Key);
                            lastTarEntry = entry.Key;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }

            return(empties);
        }
예제 #15
0
        Script LoadScript(string p, ScriptType type, Dictionary <string, string> switches = null, Dictionary <string, string[]> assertSwitches = null)
        {
            var script = new Script()
            {
                name = p.Split('\\').Last()
            };
            string pbase = "";

            ZipArchive archive  = null;
            IArchive   compress = null;

            archive = null;
            MemoryStream zrpstream = null;

            Bitmap GetBitmap(string path)
            {
                if (type == ScriptType.Folder)
                {
                    if (path == null)
                    {
                    }
                    path = Path.Combine(p, pbase, path);
                    FileStream s;
                    try
                    {
                        s = File.OpenRead(path);
                    }
                    catch { throw new Exception("Could not open " + path); }
                    Bitmap b;
                    try
                    {
                        b = new Bitmap(s);
                    }
                    catch { throw new Exception("Corrupt image: " + path); }
                    s.Close();
                    return(b);
                }
                else if (type == ScriptType.Zip || type == ScriptType.Zrp)
                {
                    path = Path.Combine(pbase, path);
                    Stream s;
                    try
                    {
                        s = archive.GetEntry(path).Open();
                    }
                    catch { throw new Exception("Could not open " + path); }
                    Bitmap b;
                    try
                    {
                        b = new Bitmap(s);
                    }
                    catch { throw new Exception("Corrupt image: " + path); }
                    s.Close();
                    return(b);
                }
                else
                {
                    path = Path.Combine(pbase, path);
                    Stream s;
                    var    e = compress.Entries.Where(a => a.Key == path).ToArray();
                    if (e.Length == 0)
                    {
                        throw new Exception("Could not open " + path);
                    }
                    s = e[0].OpenEntryStream();
                    Bitmap b;
                    try
                    {
                        b = new Bitmap(s);
                    }
                    catch { throw new Exception("Corrupt image: " + path); }
                    s.Close();
                    return(b);
                }
            }

            try
            {
                string code = "";
                if (type == ScriptType.Folder)
                {
                    var files = Directory.GetFiles(p, "*script.cs", SearchOption.AllDirectories)
                                .Where(s => s.EndsWith("\\script.cs"))
                                .Select(s => s.Substring(p.Length + 1))
                                .ToArray();
                    Array.Sort(files.Select(s => s.Length).ToArray(), files);
                    if (files.Length == 0)
                    {
                        throw new Exception("Could not find script.cs file");
                    }
                    var jsonpath = files[0];
                    pbase = jsonpath.Substring(0, jsonpath.Length - "script.cs".Length);
                    if (files.Length == 0)
                    {
                        throw new Exception("Could not find script.cs file");
                    }
                    try
                    {
                        code = File.ReadAllText(Path.Combine(p, jsonpath));
                    }
                    catch { throw new Exception("Could not read script.cs file"); }
                }
                else if (type == ScriptType.Zip || type == ScriptType.Zrp)
                {
                    if (type == ScriptType.Zrp)
                    {
                        var encoded = File.OpenRead(p);
                        var key     = new byte[16];
                        var iv      = new byte[16];
                        encoded.Read(key, 0, 16);
                        encoded.Read(iv, 0, 16);

                        zrpstream = new MemoryStream();

                        using (AesManaged aes = new AesManaged())
                        {
                            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);
                            using (CryptoStream cs = new CryptoStream(encoded, decryptor, CryptoStreamMode.Read))
                            {
                                cs.CopyTo(zrpstream);
                            }
                            zrpstream.Position = 0;
                            archive            = new ZipArchive(zrpstream);
                        }
                    }
                    else
                    {
                        archive = ZipFile.OpenRead(p);
                    }
                    var files = archive.Entries.Where(e => e.Name == "script.cs").ToArray();
                    Array.Sort(files.Select(s => s.FullName.Length).ToArray(), files);
                    if (files.Length == 0)
                    {
                        throw new Exception("Could not find script.cs file");
                    }
                    var jsonfile = files[0];
                    pbase = jsonfile.FullName.Substring(0, jsonfile.FullName.Length - "script.cs".Length);
                    using (var jfile = new StreamReader(jsonfile.Open()))
                    {
                        code = jfile.ReadToEnd();
                    }
                }
                else
                {
                    if (type == ScriptType.Rar)
                    {
                        compress = RarArchive.Open(p);
                    }
                    if (type == ScriptType.SevenZip)
                    {
                        compress = SevenZipArchive.Open(p);
                    }
                    if (type == ScriptType.Tar)
                    {
                        compress = TarArchive.Open(p);
                    }

                    var files = compress.Entries.Where(e => e.Key.EndsWith("/script.cs") || e.Key == "script.cs").ToArray();
                    Array.Sort(files.Select(s => s.Key.Length).ToArray(), files);
                    if (files.Length == 0)
                    {
                        throw new Exception("Could not find script.cs file");
                    }
                    var jsonfile = files[0];
                    pbase = jsonfile.Key.Substring(0, jsonfile.Key.Length - "script.cs".Length);
                    using (var jfile = new StreamReader(jsonfile.OpenEntryStream()))
                    {
                        code = jfile.ReadToEnd();
                    }
                }

                var fc = code.Replace(" ", "").Replace("\t", "").Replace("\n", "").Replace("\r", "");

                Dictionary <string, string> notallowed = new Dictionary <string, string>()
                {
                    { "System.IO", null },
                    { "System.Reflection", null },
                    { "Microsoft.CSharp", null },
                    { "System.Net", null },
                    { "Microsoft.VisualBasic", null },
                    { "System.Drawing", null },
                    { "System.AttributeUsage", null },
                    { "System.EnterpriseServices", null },
                    { "System.Media", null },
                    { "System.Messaging", null },
                    { "System.Printing", null },
                    { "System.Security", null },
                    { "System.ServiceModel", null },
                    { "System.ServiceProcess", null },
                    { "System.Speech", null },
                    { "System.Web", null },
                    { "System.Windows", null },
                    { "System.Xml", null },
                    { "Microsoft.Windows", null },
                    { "Microsoft.Win32", null },
                    { "Microsoft.SqlServer", null },
                    { "Microsoft.JScript", null },
                    { "Microsoft.Build", null },
                    { "Accessibility", null },
                    { "Microsoft.Activities", null },
                    { "System.Diagnostics", "random user" },
                    { "System.Runtime", "random user" },
                    { "System.Management", "random user" }
                };

                foreach (var n in notallowed)
                {
                    if (fc.Contains(n.Key))
                    {
                        if (n.Value == null)
                        {
                            throw new Exception(n.Key + " is not allowed");
                        }
                        else
                        if (fc.Contains(n.Key))
                        {
                            throw new Exception(n.Key + " is not allowed (found by " + n.Value + ")");
                        }
                    }
                }

                CompilerParameters compiler_parameters = new CompilerParameters();

                compiler_parameters.GenerateInMemory = true;

                compiler_parameters.GenerateExecutable = false;

                compiler_parameters.ReferencedAssemblies.Add(typeof(object).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(OpenTK.Vector2).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(IEnumerable <object>).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(LinkedList <object>).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(System.Drawing.Color).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(IO).Assembly.Location);
                compiler_parameters.ReferencedAssemblies.Add(typeof(System.Linq.Enumerable).Assembly.Location);

                compiler_parameters.CompilerOptions = "/optimize /unsafe /nostdlib";

                CompilerResults results = provider.CompileAssemblyFromSource(compiler_parameters, code);

                if (results.Errors.HasErrors)
                {
                    StringBuilder builder = new StringBuilder();
                    foreach (CompilerError error in results.Errors)
                    {
                        builder.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
                    }
                    throw new Exception(String.Format("Error on line {0}:\n{1}", results.Errors[0].Line, results.Errors[0].ErrorText) + "\n" + builder.ToString());
                }

                IO.loadTexture = (path, loop, linear) =>
                {
                    var bmp    = GetBitmap(path);
                    var loaded = new Texture()
                    {
                        bitmap      = bmp,
                        path        = path,
                        width       = bmp.Width,
                        height      = bmp.Height,
                        aspectRatio = bmp.Width / (double)bmp.Height,
                        looped      = loop,
                        linear      = linear
                    };
                    script.textures.Add(loaded);
                    return(loaded);
                };

                IO.loadFont = (size, name, style, chars) =>
                {
                    var font = new Font()
                    {
                        charMap       = chars,
                        fontName      = name,
                        fontPixelSize = size,
                        fontStyle     = style
                    };
                    script.fonts.Add(font);
                    return(font);
                };

                Assembly assembly   = results.CompiledAssembly;
                var      renderType = assembly.GetType("Script");
                var      instance   = (dynamic)Activator.CreateInstance(renderType);
                script.instance   = instance;
                script.renderType = renderType;

                IO.callLoadFunction(script.instance);

                if (renderType.GetField("Description") != null)
                {
                    script.description = instance.Description;
                }
                if (renderType.GetField("Preview") != null)
                {
                    script.preview = GetBitmap(instance.Preview);
                }

                if (renderType.GetMethod("Load") == null)
                {
                    throw new Exception("Load method required");
                }
                if (renderType.GetMethod("Render") == null)
                {
                    throw new Exception("Render method required");
                }

                if (renderType.GetMethod("RenderInit") != null)
                {
                    script.hasPreRender = true;
                }
                if (renderType.GetMethod("RenderDispose") != null)
                {
                    script.hasPostRender = true;
                }

                bool hasVar(string name, Type ftype)
                {
                    if (renderType.GetField(name) != null)
                    {
                        if (ftype.IsAssignableFrom(renderType.GetField(name).FieldType))
                        {
                            return(true);
                        }
                    }
                    if (renderType.GetProperty(name) != null)
                    {
                        if (ftype.IsAssignableFrom(renderType.GetProperty(name).PropertyType))
                        {
                            return(true);
                        }
                    }
                    return(false);
                }

                if (hasVar("ManualNoteDelete", typeof(bool)))
                {
                    script.hasManualNoteDelete = true;
                }
                if (hasVar("NoteCollectorOffset", typeof(double)))
                {
                    script.hasCollectorOffset = true;
                }
                if (hasVar("NoteScreenTime", typeof(double)))
                {
                    script.hasNoteScreenTime = true;
                }
                if (hasVar("LastNoteCount", typeof(long)))
                {
                    script.hasNoteCount = true;
                }
                if (hasVar("UseProfiles", typeof(bool)))
                {
                    script.hasProfiles = script.instance.UseProfiles;
                }

                if (hasVar("SettingsUI", typeof(IEnumerable <UISetting>)))
                {
                    script.uiSettings = instance.SettingsUI;
                }
            }
            catch (Exception e)
            {
                if (e is TargetInvocationException)
                {
                    e = e.InnerException;
                }
                script.error       = true;
                script.description = e.Message;
            }
            finally
            {
                if (archive != null)
                {
                    archive.Dispose();
                }
                if (zrpstream != null)
                {
                    zrpstream.Dispose();
                }
                if (compress != null)
                {
                    compress.Dispose();
                }
            }
            return(script);
        }
예제 #16
0
        /// <summary>
        /// Write a set of input files to a tape archive (assuming the same output archive name)
        /// </summary>
        /// <param name="inputFiles">Input files to be moved</param>
        /// <param name="outDir">Output directory to build to</param>
        /// <param name="rom">DatItem representing the new information</param>
        /// <returns>True if the archive was written properly, false otherwise</returns>
        public override bool Write(List <string> inputFiles, string outDir, List <Rom> roms)
        {
            bool   success  = false;
            string tempFile = Path.Combine(outDir, $"tmp{Guid.NewGuid()}");

            // If either list of roms is null or empty, return
            if (inputFiles == null || roms == null || inputFiles.Count == 0 || roms.Count == 0)
            {
                return(success);
            }

            // If the number of inputs is less than the number of available roms, return
            if (inputFiles.Count < roms.Count)
            {
                return(success);
            }

            // If one of the files doesn't exist, return
            foreach (string file in inputFiles)
            {
                if (!File.Exists(file))
                {
                    return(success);
                }
            }

            // Get the output archive name from the first rebuild rom
            string archiveFileName = Path.Combine(outDir, Sanitizer.RemovePathUnsafeCharacters(roms[0].Machine.Name) + (roms[0].Machine.Name.EndsWith(".tar") ? string.Empty : ".tar"));

            // Set internal variables
            TarArchive oldTarFile = TarArchive.Create();
            TarArchive tarFile    = TarArchive.Create();

            try
            {
                // If the full output path doesn't exist, create it
                if (!Directory.Exists(Path.GetDirectoryName(archiveFileName)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(archiveFileName));
                }

                // If the archive doesn't exist, create it and put the single file
                if (!File.Exists(archiveFileName))
                {
                    // Map all inputs to index
                    Dictionary <string, int> inputIndexMap = new Dictionary <string, int>();
                    for (int i = 0; i < inputFiles.Count; i++)
                    {
                        inputIndexMap.Add(roms[i].Name.Replace('\\', '/'), i);
                    }

                    // Sort the keys in TZIP order
                    List <string> keys = inputIndexMap.Keys.ToList();
                    keys.Sort(ZipFile.TrrntZipStringCompare);

                    // Now add all of the files in order
                    foreach (string key in keys)
                    {
                        // Get the index mapped to the key
                        int index = inputIndexMap[key];

                        // Get temporary date-time if possible
                        DateTime?usableDate = null;
                        if (UseDates && !string.IsNullOrWhiteSpace(roms[index].Date) && DateTime.TryParse(roms[index].Date.Replace('\\', '/'), out DateTime dt))
                        {
                            usableDate = dt;
                        }

                        // Copy the input stream to the output
                        tarFile.AddEntry(roms[index].Name, FileExtensions.TryOpenRead(inputFiles[index]), size: roms[index].Size ?? 0, modified: usableDate);
                    }
                }

                // Otherwise, sort the input files and write out in the correct order
                else
                {
                    // Open the old archive for reading
                    oldTarFile = TarArchive.Open(archiveFileName);

                    // Get a list of all current entries
                    List <string> entries = oldTarFile.Entries.Select(i => i.Key).ToList();

                    // Map all inputs to index
                    Dictionary <string, int> inputIndexMap = new Dictionary <string, int>();
                    for (int i = 0; i < inputFiles.Count; i++)
                    {
                        // If the old one contains the new file, then just skip out
                        if (entries.Contains(roms[i].Name.Replace('\\', '/')))
                        {
                            continue;
                        }

                        inputIndexMap.Add(roms[i].Name.Replace('\\', '/'), -(i + 1));
                    }

                    // Then add all of the old entries to it too
                    for (int i = 0; i < entries.Count; i++)
                    {
                        inputIndexMap.Add(entries[i], i);
                    }

                    // If the number of entries is the same as the old archive, skip out
                    if (inputIndexMap.Keys.Count <= entries.Count)
                    {
                        success = true;
                        return(success);
                    }

                    // Get the order for the entries with the new file
                    List <string> keys = inputIndexMap.Keys.ToList();
                    keys.Sort(ZipFile.TrrntZipStringCompare);

                    // Copy over all files to the new archive
                    foreach (string key in keys)
                    {
                        // Get the index mapped to the key
                        int index = inputIndexMap[key];

                        // If we have the input file, add it now
                        if (index < 0)
                        {
                            // Get temporary date-time if possible
                            DateTime?usableDate = null;
                            if (UseDates && !string.IsNullOrWhiteSpace(roms[-index - 1].Date) && DateTime.TryParse(roms[-index - 1].Date.Replace('\\', '/'), out DateTime dt))
                            {
                                usableDate = dt;
                            }

                            // Copy the input file to the output
                            tarFile.AddEntry(roms[-index - 1].Name, FileExtensions.TryOpenRead(inputFiles[-index - 1]), size: roms[-index - 1].Size ?? 0, modified: usableDate);
                        }

                        // Otherwise, copy the file from the old archive
                        else
                        {
                            // Get the stream from the original archive
                            TarArchiveEntry tae   = oldTarFile.Entries.ElementAt(index);
                            MemoryStream    entry = new MemoryStream();
                            tae.OpenEntryStream().CopyTo(entry);

                            // Copy the input stream to the output
                            tarFile.AddEntry(key, entry, size: tae.Size, modified: tae.LastModifiedTime);
                        }
                    }
                }

                // Close the output tar file
                tarFile.SaveTo(tempFile, new WriterOptions(CompressionType.None));

                success = true;
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                success = false;
            }
            finally
            {
                tarFile.Dispose();
                oldTarFile.Dispose();
            }

            // If the old file exists, delete it and replace
            if (File.Exists(archiveFileName))
            {
                FileExtensions.TryDelete(archiveFileName);
            }
            File.Move(tempFile, archiveFileName);

            return(true);
        }
예제 #17
0
        public Func <HttpContent, Task <T> > CreateDeserializer <T>()
        {
            if (typeof(T) == typeof(ZipArchive))
            {
                return(async(content) =>
                {
                    var ms = new MemoryStream();
                    await content.CopyToAsync(ms);

                    var arch = ZipArchive.Open(ms, GetReaderOptions().ReaderOptions);
                    return (T)((object)arch);
                });
            }
            if (typeof(T) == typeof(RarArchive))
            {
                return(async(content) =>
                {
                    var ms = new MemoryStream();
                    await content.CopyToAsync(ms);

                    ms.Position = 0;
                    var arch = RarArchive.Open(ms, GetReaderOptions().ReaderOptions);
                    return (T)((object)arch);
                });
            }
            if (typeof(T) == typeof(GZipArchive))
            {
                return(async(content) =>
                {
                    var ms = new MemoryStream();
                    await content.CopyToAsync(ms);

                    ms.Position = 0;
                    var arch = GZipArchive.Open(ms, GetReaderOptions().ReaderOptions);
                    return (T)((object)arch);
                });
            }
            if (typeof(T) == typeof(SevenZipArchive))
            {
                return(async(content) =>
                {
                    var ms = new MemoryStream();
                    await content.CopyToAsync(ms);

                    ms.Position = 0;
                    var arch = SevenZipArchive.Open(ms, GetReaderOptions().ReaderOptions);
                    return (T)((object)arch);
                });
            }
            if (typeof(T) == typeof(TarArchive))
            {
                return(async(content) =>
                {
                    if (GetReaderOptions().TarArchivesAreGziped)
                    {
                        var outerms = new MemoryStream();
                        await content.CopyToAsync(outerms);

                        outerms.Position = 0;
                        var gzarch = GZipArchive.Open(outerms, GetReaderOptions().ReaderOptions);
                        var entry = gzarch.Entries.FirstOrDefault();
                        using (var readGzStream = entry.OpenEntryStream())
                        {
                            var innerms = new MemoryStream();
                            readGzStream.CopyTo(innerms);
                            innerms.Position = 0;
                            var tararch = TarArchive.Open(innerms, GetReaderOptions().ReaderOptions);
                            return (T)((object)tararch);
                        }
                    }
                    else
                    {
                        var ms = new MemoryStream();
                        await content.CopyToAsync(ms);

                        ms.Position = 0;
                        var arch = TarArchive.Open(ms, GetReaderOptions().ReaderOptions);
                        return (T)((object)arch);
                    }
                });
            }
            else
            {
                throw new NotSupportedException("Type not supported");
            }
        }
예제 #18
0
        /// <summary>
        /// Write an input stream to a tape archive
        /// </summary>
        /// <param name="inputStream">Input stream to be moved</param>
        /// <param name="outDir">Output directory to build to</param>
        /// <param name="rom">DatItem representing the new information</param>
        /// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param>
        /// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param>
        /// <returns>True if the archive was written properly, false otherwise</returns>
        public override bool Write(Stream inputStream, string outDir, Rom rom, bool date = false, bool romba = false)
        {
            bool   success  = false;
            string tempFile = Path.Combine(outDir, "tmp" + Guid.NewGuid().ToString());

            // If either input is null or empty, return
            if (inputStream == null || rom == null || rom.Name == null)
            {
                return(success);
            }

            // If the stream is not readable, return
            if (!inputStream.CanRead)
            {
                return(success);
            }

            // Get the output archive name from the first rebuild rom
            string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(rom.MachineName) + (rom.MachineName.EndsWith(".tar") ? "" : ".tar"));

            // Set internal variables
            TarArchive oldTarFile = TarArchive.Create();
            TarArchive tarFile    = TarArchive.Create();

            try
            {
                // If the full output path doesn't exist, create it
                if (!Directory.Exists(Path.GetDirectoryName(archiveFileName)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(archiveFileName));
                }

                // If the archive doesn't exist, create it and put the single file
                if (!File.Exists(archiveFileName))
                {
                    // Get temporary date-time if possible
                    DateTime?usableDate = null;
                    if (date && !String.IsNullOrWhiteSpace(rom.Date) && DateTime.TryParse(rom.Date.Replace('\\', '/'), out DateTime dt))
                    {
                        usableDate = dt;
                    }

                    // Copy the input stream to the output
                    inputStream.Seek(0, SeekOrigin.Begin);
                    tarFile.AddEntry(rom.Name, inputStream, size: rom.Size, modified: usableDate);
                }

                // Otherwise, sort the input files and write out in the correct order
                else
                {
                    // Open the old archive for reading
                    oldTarFile = TarArchive.Open(archiveFileName);

                    // Get a list of all current entries
                    List <string> entries = oldTarFile.Entries.Select(i => i.Key).ToList();

                    // Map all inputs to index
                    Dictionary <string, int> inputIndexMap = new Dictionary <string, int>();

                    // If the old one doesn't contain the new file, then add it
                    if (!entries.Contains(rom.Name.Replace('\\', '/')))
                    {
                        inputIndexMap.Add(rom.Name.Replace('\\', '/'), -1);
                    }

                    // Then add all of the old entries to it too
                    for (int i = 0; i < entries.Count; i++)
                    {
                        inputIndexMap.Add(entries[i], i);
                    }

                    // If the number of entries is the same as the old archive, skip out
                    if (inputIndexMap.Keys.Count <= entries.Count)
                    {
                        success = true;
                        return(success);
                    }

                    // Get the order for the entries with the new file
                    List <string> keys = inputIndexMap.Keys.ToList();
                    keys.Sort(ZipFile.TorrentZipStringCompare);

                    // Copy over all files to the new archive
                    foreach (string key in keys)
                    {
                        // Get the index mapped to the key
                        int index = inputIndexMap[key];

                        // Get temporary date-time if possible
                        DateTime?usableDate = null;
                        if (date && !String.IsNullOrWhiteSpace(rom.Date) && DateTime.TryParse(rom.Date.Replace('\\', '/'), out DateTime dt))
                        {
                            usableDate = dt;
                        }

                        // If we have the input file, add it now
                        if (index < 0)
                        {
                            // Copy the input file to the output
                            inputStream.Seek(0, SeekOrigin.Begin);
                            tarFile.AddEntry(rom.Name, inputStream, size: rom.Size, modified: usableDate);
                        }

                        // Otherwise, copy the file from the old archive
                        else
                        {
                            // Get the stream from the original archive
                            TarArchiveEntry tae   = oldTarFile.Entries.ElementAt(index);
                            MemoryStream    entry = new MemoryStream();
                            tae.OpenEntryStream().CopyTo(entry);

                            // Copy the input stream to the output
                            tarFile.AddEntry(key, entry, size: tae.Size, modified: tae.LastModifiedTime);
                        }
                    }
                }

                // Close the output tar file
                tarFile.SaveTo(tempFile, new WriterOptions(CompressionType.None));

                success = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                success = false;
            }
            finally
            {
                inputStream.Dispose();
                tarFile.Dispose();
                oldTarFile.Dispose();
            }

            // If the old file exists, delete it and replace
            if (File.Exists(archiveFileName))
            {
                Utilities.TryDeleteFile(archiveFileName);
            }
            File.Move(tempFile, archiveFileName);

            return(success);
        }
예제 #19
0
        public async Task Unpack(VirtualFile file, VirtualDirectory destination,
                                 IProgressNotifier parentProgress = null, ChangeObservable observable = null)
        {
            if (Path.GetExtension(file.Name)?.Equals(".zip", StringComparison.OrdinalIgnoreCase) == true)
            {
                await UnpackZipFile().ConfigureAwait(false);
            }
            else if (file.Name.EndsWith(".tar.xz", StringComparison.OrdinalIgnoreCase))
            {
                UnpackTarXzFile(file);
            }
            else if (Path.GetExtension(file.Name)?.Equals(".xz", StringComparison.OrdinalIgnoreCase) == true)
            {
                UnpackXzFile(file);
            }
            else if (Path.GetExtension(file.Name)?.Equals(".tar", StringComparison.OrdinalIgnoreCase) == true)
            {
                UnpackTarFile(file);
            }
            else if (Path.GetExtension(file.Name)?.Equals(".sh", StringComparison.OrdinalIgnoreCase) == true &&
                     environmentService.Platform != OSPlatform.Windows)
            {
                await UnpackSelfExtractingShellScript().ConfigureAwait(false);
            }
            else
            {
                throw new UnsupportedArchiveFormatException(file.FullName);
            }

            async Task UnpackSelfExtractingShellScript()
            {
                ValidateShellScript();
                StringBuilderUserInterface userInterface = new StringBuilderUserInterface(log, writeInformation: true, writeError: true);

                try
                {
                    using (parentProgress?.SpawnInfiniteProgress("Executing the shell script."))
                        using (IProcess process = processManager.StartProcess(file.FullName, $"-y -d \"{destination.FullName}\"", userInterface))
                        {
                            await process.WaitForExitAsync().ConfigureAwait(false);

                            if (process.ExitCode != 0)
                            {
                                throw new UnsupportedArchiveFormatException(file.FullName,
                                                                            new FormattableException(
                                                                                $"An error occured while executing the script.{Environment.NewLine}" +
                                                                                $"{userInterface.Error}"));
                            }
                        }
                }
                catch (Exception e)
                {
                    if (e is FormattableException)
                    {
                        throw;
                    }
                    throw new UnsupportedArchiveFormatException(file.FullName,
                                                                new FormattableException(
                                                                    $"An exception occured while executing the script.{Environment.NewLine}" +
                                                                    $"{e.Message}", e));
                }

                void ValidateShellScript()
                {
                    StringBuilderUserInterface validationUserInterface = new StringBuilderUserInterface(log, writeInformation: true, writeError: true);

                    try
                    {
                        using (IProcess process = processManager.StartProcess(file.FullName, "--help", validationUserInterface))
                        {
                            process.WaitForExit();
                        }
                    }
                    catch (UnauthorizedAccessException e)
                    {
                        throw new UnsupportedArchiveFormatException(file.FullName,
                                                                    new FormattableException(
                                                                        $"An exception occured while inspecting the script.{Environment.NewLine}" +
                                                                        $"This excpetion can occur when the file is not marked as executable.{Environment.NewLine}" +
                                                                        $"{e.Message}", e));
                    }
                    catch (Exception e)
                    {
                        if (e is FormattableException)
                        {
                            throw;
                        }
                        throw new UnsupportedArchiveFormatException(file.FullName,
                                                                    new FormattableException(
                                                                        $"An exception occured while inspecting the script.{Environment.NewLine}" +
                                                                        $"{e.Message}", e));
                    }

                    if (!Regex.IsMatch(validationUserInterface.Information,
                                       @"(?=.*(?:usage|Usage)).*(?=.*-y)(?=.*-d)"))
                    {
                        throw new UnsupportedArchiveFormatException(file.FullName,
                                                                    new FormattableException($"Did not find the expected usage information.{Environment.NewLine}" +
                                                                                             $"The expected information need to include the options '-y' and '-d'.{Environment.NewLine}" +
                                                                                             $"The following usage information was given:{Environment.NewLine}" +
                                                                                             $"{validationUserInterface.Information}"));
                    }
                }
            }

            async Task UnpackZipFile()
            {
                using (Stream fileStream = file.OpenRead())
                    using (ZipFile zipFile = new ZipFile(fileStream))
                        using (IProgressNotifier mainProgress = parentProgress?.Spawn(2, $"Extracting {file.FullName} to {destination.FullName}."))
                        {
                            archiveResultBuilder.Clear();
                            using (mainProgress?.SpawnInfiniteProgress("Test archive integrity."))
                            {
                                ZipFile copy = zipFile;
                                await Task.Run(() =>
                                {
                                    if (!copy.TestArchive(true, TestStrategy.FindAllErrors, ResultHandler))
                                    {
                                        throw new UnsupportedArchiveFormatException(
                                            file.FullName, new FormattableException(archiveResultBuilder.ToString()));
                                    }
                                }).ConfigureAwait(false);
                            }

                            double increment = (double)Constants.ProgressMaxResolution / zipFile.Count + 1;
                            using (IProgressNotifier extractProgress = mainProgress?.Spawn(Constants.ProgressMaxResolution, "Extract files"))
                            {
                                foreach (ZipEntry zipEntry in zipFile)
                                {
                                    extractProgress?.TickIncrement(increment);
                                    if (!zipEntry.IsFile)
                                    {
                                        continue;   // Ignore directories
                                    }

                                    byte[] buffer = new byte[Constants.StreamCopyBufferSize]; // 4K is optimum

                                    using (Stream zipStream = zipFile.GetInputStream(zipEntry))
                                    {
                                        string[]         path            = fileSystem.GetPath(zipEntry.Name);
                                        VirtualDirectory fileDestination = destination.Directory(path.Take(path.Length - 1).ToArray());
                                        VirtualFile      entryFile       = fileDestination.File(path.Last());

                                        // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                                        // of the file, but does not waste memory.
                                        using (Stream streamWriter = entryFile.OpenWrite())
                                        {
                                            StreamUtils.Copy(zipStream, streamWriter, buffer);
                                        }
                                    }
                                }
                            }
                        }
            }

            VirtualFile UnpackXzFile(VirtualFile packedFile)
            {
                using (Stream fileStream = packedFile.OpenRead())
                    using (XZStream xzStream = new XZStream(fileStream))
                        using (parentProgress?.SpawnInfiniteProgress($"Extracting {packedFile.Name}..."))
                        {
                            string[] path             = fileSystem.GetPath(packedFile.FullName);
                            string   relativeFilePath = path.Last().Substring(0, path.Last().LastIndexOf(".xz", StringComparison.OrdinalIgnoreCase));
                            if (destination.FileExists(relativeFilePath))
                            {
                                destination.File(relativeFilePath).Delete();
                            }
                            VirtualFile destinationFile = destination.File(relativeFilePath);
                            observable?.OnNext(new Change(() => destinationFile.Restore()));

                            byte[] buffer = new byte[Constants.StreamCopyBufferSize]; // 4K is optimum

                            using (Stream streamWriter = destinationFile.OpenWrite())
                            {
                                StreamUtils.Copy(xzStream, streamWriter, buffer);
                                return(destinationFile);
                            }
                        }
            }

            void UnpackTarFile(VirtualFile packedFile)
            {
                //sharpcompress
                using (Stream fileStream = packedFile.OpenRead())
                    using (TarArchive tarArchive = TarArchive.Open(fileStream))
                    {
                        double increment = (double)Constants.ProgressMaxResolution / tarArchive.Entries.Count;
                        using (IProgressNotifier extractProgress = parentProgress?.Spawn(Constants.ProgressMaxResolution, "Extracting .tar archive"))
                        {
                            foreach (TarArchiveEntry tarEntry in tarArchive.Entries)
                            {
                                extractProgress?.TickIncrement(increment);
                                if (tarEntry.IsDirectory)
                                {
                                    continue;       // Ignore directories
                                }

                                byte[] buffer = new byte[Constants.StreamCopyBufferSize]; // 4K is optimum

                                using (Stream tarStream = tarEntry.OpenEntryStream())
                                {
                                    string[]         path            = fileSystem.GetPath(tarEntry.Key);
                                    VirtualDirectory fileDestination = destination.Directory(path.Take(path.Length - 1).ToArray());
                                    if (fileDestination.FileExists(path.Last()))
                                    {
                                        fileDestination.File(path.Last()).Delete();
                                    }
                                    VirtualFile entryFile = fileDestination.File(path.Last());
                                    observable?.OnNext(new Change(() => entryFile.Restore()
                                                                  //, $"Unpack {tarEntry.Key}."
                                                                  ));

                                    //Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                                    // of the file, but does not waste memory.
                                    using (Stream streamWriter = entryFile.OpenWrite())
                                    {
                                        StreamUtils.Copy(tarStream, streamWriter, buffer);
                                    }
                                }
                            }
                        }
                    }
            }

            void UnpackTarXzFile(VirtualFile packedFile)
            {
                using (IProgressNotifier subProgress = parentProgress?.Spawn(2))
                {
                    parentProgress = subProgress;
                    VirtualFile tarFile = UnpackXzFile(packedFile);
                    UnpackTarFile(tarFile);
                    tarFile.Delete();
                }
            }
        }
예제 #20
0
 protected override AbstractArchive <TarArchiveEntry, TarVolume> OpenArchive(Stream stream)
 => TarArchive.Open(stream);
예제 #21
0
        public override TemporaryDirectory DownloadPackage(Upset package)
        {
            TemporaryDirectory td = new TemporaryDirectory();

            string sourcePath = string.Format(formatPattern, Path, System.IO.Path.DirectorySeparatorChar, package.MetaInformation.dirName);

            if (Directory.Exists(sourcePath))
            {
                FileSystemUtil.CopyDirectoryWithMeta(sourcePath, td.Path);
            }
            else if (IsUnityPackage(sourcePath))
            {
                using (MemoryStream TarArchiveMS = new MemoryStream())
                {
                    using (FileStream originalFileStream = new FileStream(sourcePath, FileMode.Open))
                    {
                        using (GZipStream decompressionStream =
                                   new GZipStream(originalFileStream, CompressionMode.Decompress))
                        {
                            decompressionStream.CopyTo(TarArchiveMS);
                            TarArchiveMS.Position = 0;
                        }
                    }
                    TarArchive reader = TarArchive.Open(TarArchiveMS);

                    string       assetPath = null;
                    MemoryStream assetMS   = null;
                    MemoryStream metaMS    = null;

                    foreach (TarArchiveEntry entry in reader.Entries)
                    {
                        if (entry.IsDirectory)
                        {
                            continue;
                        }

                        if (entry.Key.EndsWith("asset"))
                        {
                            if (assetMS != null)
                            {
                                throw new InvalidOperationException("Unexpected state: assetMS not null");
                            }

                            assetMS = new MemoryStream();
                            entry.WriteTo(assetMS);
                            assetMS.Position = 0;
                            continue;
                        }
                        if (entry.Key.EndsWith("metaData"))
                        {
                            throw new NotSupportedException("The package has been packed by a Unity version prior to Unity5, and we do not support this. Contact the package maintainer for updated version.");
                        }
                        if (entry.Key.EndsWith("meta"))
                        {
                            metaMS = new MemoryStream();
                            entry.WriteTo(metaMS);
                            metaMS.Position = 0;
                            continue;
                        }
                        if (entry.Key.EndsWith("pathname"))
                        {
                            MemoryStream MSM = new MemoryStream();
                            entry.WriteTo(MSM);
                            MSM.Position = 0;
                            using (StreamReader SR = new StreamReader(MSM))
                            {
                                assetPath = SR.ReadToEnd().Split('\n')[0];
                            }
                        }
                        if (assetPath != null)
                        {
                            if (assetMS == null)
                            {
                                // these are for directories inside the file
                                Debug.Log("path not null " + assetPath + " but asset not yet read");
                                assetPath = null;
                                continue;
                            }
                            string AssetPath    = td.Path + System.IO.Path.DirectorySeparatorChar + assetPath.Replace('/', System.IO.Path.DirectorySeparatorChar);
                            var    AssetPathDir = new FileInfo(AssetPath).Directory.FullName;
                            if (!Directory.Exists(AssetPathDir))
                            {
                                Directory.CreateDirectory(AssetPathDir);
                            }
                            using (FileStream FS = new FileStream(AssetPath, FileMode.Create))
                            {
                                assetMS.CopyTo(FS);
                            }
                            assetMS.Dispose();
                            assetMS = null;
                            if (metaMS != null)
                            {
                                string MetaPath = AssetPath + ".meta";
                                using (FileStream FS = new FileStream(MetaPath, FileMode.Create))
                                {
                                    metaMS.CopyTo(FS);
                                }
                                metaMS.Dispose();
                                metaMS = null;
                            }

                            assetPath = null;
                        }
                    }
                }

                string   commonRoot    = "";
                string[] directories   = Directory.GetDirectories(td.Path);
                string   inspectedPath = td.Path;

                // Lone directory
                while (directories.Length == 1)
                {
                    string[] entries = Directory.GetFiles(inspectedPath);
                    if (entries.Length > 1 || (entries.Length == 1 && !entries[0].EndsWith(".meta")))
                    {
                        break;
                    }

                    commonRoot    = System.IO.Path.Combine(commonRoot, directories[0]);
                    inspectedPath = System.IO.Path.Combine(td.Path, commonRoot);
                    directories   = Directory.GetDirectories(inspectedPath);
                }

                if (commonRoot != "")
                {
                    FileSystemUtil.MoveDirectoryContent(inspectedPath, td.Path);
                    Directory.Delete(System.IO.Path.Combine(td.Path, commonRoot.Replace(td.Path, "").Split(System.IO.Path.DirectorySeparatorChar)[1]), true);
                    if (package.Configuration != null)
                    {
                        foreach (InstallSpecPath spec in package.Configuration)
                        {
                            spec.Path.Replace(commonRoot, "");
                        }
                    }
                }
            }
            else
            {
                Debug.LogError(string.Format("Package {0} version {1} has an unexpected format and cannot be downloaded ", package.PackageName, package.PackageVersion));
            }

            return(td);
        }
예제 #22
0
 /// <summary>
 /// Create file provider that reads tar content from a readable and seekable stream.
 ///
 /// Note, that one file entry stream is allowed to be open at the same time. Others will wait in lock.
 ///
 /// Does not dispose the <paramref name="stream"/> with the file provider.
 /// To dispose stream along with its file provider, construct it like this: <code>new TarFileProvider(stream).AddDisposable(stream)</code>
 /// </summary>
 /// <param name="stream"></param>
 /// <param name="pathHint">(optional) clue of the file that is being opened</param>
 /// <param name="dateTime">Date time for folder entries</param>
 /// <param name="convertBackslashesToSlashes">if true converts '\' to '/'</param>
 /// <exception cref="IOException">On I/O error</exception>
 /// <exception cref="PackageException.LoadError">on tar error</exception>
 public TarFileProvider(Stream stream, String pathHint = null, DateTimeOffset?dateTime = default, bool convertBackslashesToSlashes = defaultConvertBackslashesToSlashes) : base(TarArchive.Open(stream), pathHint, dateTime, convertBackslashesToSlashes)
 {
 }
예제 #23
0
        /// <summary>
        /// Extracts a package at archivePath, and unpacks it at destinationPath
        /// </summary>
        public void Extract(string archivePath, string destinationPath)
        {
            using (MemoryStream TarArchiveMS = new MemoryStream())
            {
                using (FileStream originalFileStream = new FileStream(archivePath, FileMode.Open))
                {
                    using (GZipStream decompressionStream =
                               new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(TarArchiveMS);
                        TarArchiveMS.Position = 0;
                    }
                }
                TarArchive reader = TarArchive.Open(TarArchiveMS);

                string       assetPath = null;
                MemoryStream assetMS   = null;
                MemoryStream metaMS    = null;
                foreach (TarArchiveEntry entry in reader.Entries)
                {
                    if (entry.IsDirectory)
                    {
                        continue;
                    }

                    if (entry.Key.EndsWith("asset"))
                    {
                        if (assetMS != null)
                        {
                            throw new InvalidOperationException("Unexpected state: assetMS not null");
                        }

                        assetMS = new MemoryStream();
                        entry.WriteTo(assetMS);
                        assetMS.Position = 0;
                        continue;
                    }
                    if (entry.Key.EndsWith("metaData"))
                    {
                        throw new NotSupportedException("The package has been packed by a Unity version prior to Unity5, and we do not support this. Contact the package maintainer for updated version.");
                    }
                    if (entry.Key.EndsWith("meta"))
                    {
                        metaMS = new MemoryStream();
                        entry.WriteTo(metaMS);
                        metaMS.Position = 0;
                        continue;
                    }
                    if (entry.Key.EndsWith("pathname"))
                    {
                        MemoryStream MSM = new MemoryStream();
                        entry.WriteTo(MSM);
                        MSM.Position = 0;
                        using (StreamReader SR = new StreamReader(MSM))
                        {
                            assetPath = SR.ReadToEnd().Split('\n')[0];
                        }
                    }
                    if (assetPath != null)
                    {
                        string AssetPath = System.IO.Path.Combine(destinationPath, assetPath.Replace('/', System.IO.Path.DirectorySeparatorChar));
                        if (assetMS == null)
                        {
                            // asset is a directory
                            if (!Directory.Exists(AssetPath))
                            {
                                Directory.CreateDirectory(AssetPath);
                            }
                            if (metaMS != null)
                            {
                                string MetaPath = AssetPath + ".meta";
                                using (FileStream FS = new FileStream(MetaPath, FileMode.Create))
                                {
                                    metaMS.CopyTo(FS);
                                }
                                metaMS.Dispose();
                                metaMS = null;
                            }
                            else
                            {
                                // asset is a broken directory - missing meta
                                Debug.LogError("Directory at path " + assetPath + " doesn't have its meta.");
                            }
                            assetPath = null;
                            continue;
                        }
                        var AssetPathDir = new FileInfo(AssetPath).Directory.FullName;
                        if (!Directory.Exists(AssetPathDir))
                        {
                            Directory.CreateDirectory(AssetPathDir);
                        }
                        using (FileStream FS = new FileStream(AssetPath, FileMode.Create))
                        {
                            assetMS.CopyTo(FS);
                        }
                        assetMS.Dispose();
                        assetMS = null;
                        if (metaMS != null)
                        {
                            string MetaPath = AssetPath + ".meta";
                            using (FileStream FS = new FileStream(MetaPath, FileMode.Create))
                            {
                                metaMS.CopyTo(FS);
                            }
                            metaMS.Dispose();
                            metaMS = null;
                        }
                        assetPath = null;
                    }
                }
            }
        }
예제 #24
0
 /// <summary>
 /// Open .tar file for reading. Opening from a file allows concurrent reading of tar entries.
 /// </summary>
 /// <param name="filename">file name</param>
 /// <param name="pathHint">(optional) clue of the file that is being opened</param>
 /// <param name="dateTime"></param>
 /// <param name="convertBackslashesToSlashes">if true converts '\' to '/'</param>
 /// <exception cref="IOException">On I/O error</exception>
 /// <exception cref="PackageException.LoadError">on tar error</exception>
 public TarFileProvider(string filename, String pathHint = null, DateTimeOffset?dateTime = default, bool convertBackslashesToSlashes = defaultConvertBackslashesToSlashes) : base(() => TarArchive.Open(filename), pathHint, dateTime ?? File.GetLastWriteTimeUtc(filename), convertBackslashesToSlashes)
 {
 }