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()); } } }
/// <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"); }
/// <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"); }
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); }
/// <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, }; }
/// <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); }
/// <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"); }
/// <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); }
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); } }
/// <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"); } }
/// <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."); } }
/// <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); }
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); }
/// <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); }
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"); } }
/// <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); }
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(); } } }
protected override AbstractArchive <TarArchiveEntry, TarVolume> OpenArchive(Stream stream) => TarArchive.Open(stream);
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); }
/// <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) { }
/// <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; } } } }
/// <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) { }