/// <summary> /// Read file entry /// </summary> /// <param name="entry"></param> /// <returns></returns> public Memory <byte> ReadEntry(LINKDATAEntry entry) { var pointer = entry.Offset * Header.OffsetMultiplier; var buffer = new Span <byte>(new byte[entry.Size]); DataStream.Position = pointer; DataStream.Read(buffer); return(entry.DecompressedSize > 0 ? new Memory <byte>(StreamCompression.Decompress(buffer, new CompressionOptions { Length = entry.DecompressedSize, PrefixSize = true }).ToArray()) : new Memory <byte>(buffer.ToArray())); }
private static void Main(string[] args) { Logger.PrintVersion("Cethleann"); var flags = CommandLineFlags.ParseFlags <GzFlags>(CommandLineFlags.PrintHelp, args); if (flags == null) { return; } var files = new List <string>(); foreach (var arg in flags.Paths) { if (!Directory.Exists(arg)) { files.Add(arg); continue; } files.AddRange(Directory.GetFiles(arg, flags.Mask, SearchOption.AllDirectories)); } Func <byte[], byte[]>?method = null; string?ext = null; var options = new CompressionOptions { BlockSize = flags.BlockSize, Alignment = flags.Alignment, CompressionLevel = flags.Level, Length = flags.Length, ForceLastBlock = flags.CompressLast, PrefixSize = flags.PrefixedSize, Type = flags.Type }; if (flags.IsDz) { ext = ".dz"; if (flags.Compress) { method = bytes => DzCompression.Compress(bytes, options).ToArray(); } else { method = bytes => DzCompression.Decompress(bytes, options).ToArray(); } } else if (flags.IsStream) { ext = ".zl"; if (flags.Compress) { method = bytes => StreamCompression.Compress(bytes, options).ToArray(); } else { method = bytes => StreamCompression.Decompress(bytes, options).ToArray(); } } else if (flags.IsStream8000) { ext = ".z"; if (flags.Compress) { method = bytes => Stream8000Compression.Compress(bytes, options).ToArray(); } else { method = bytes => Stream8000Compression.Decompress(bytes, options).ToArray(); } } else if (flags.IsTable) { ext = ".gz"; if (flags.Compress) { method = bytes => TableCompression.Compress(bytes, options).ToArray(); } else { method = bytes => TableCompression.Decompress(bytes, options).ToArray(); } } if (method == null) { Logger.Error("Cethleann", "You must specify a compression method!"); return; } foreach (var file in files) { var target = flags.Compress ? file + ext : Path.Combine(Path.GetDirectoryName(file) ?? "", Path.GetFileNameWithoutExtension(file)); var baseTarget = target; var modulo = 0; while (File.Exists(target) && flags.Compress) { target = baseTarget + $"_{++modulo}"; } Logger.Info("Cethleann", $"{(flags.Compress ? "C" : "Dec")}ompressing {Path.GetFileName(file)} to {target}"); var bytes = File.ReadAllBytes(file); if (bytes.Length == 0) { Logger.Info("Cethleann", $"{Path.GetFileName(file)} is empty"); continue; } File.WriteAllBytes(target, method(bytes)); if (flags.Delete) { File.Delete(file); } } }
private static void Main(string[] args) { Logger.PrintVersion("Cethleann"); var flags = CommandLineFlags.ParseFlags <DataExporterFlags>(CommandLineFlags.PrintHelp, args); if (flags == null) { return; } IManagedFS?fs = default; if (flags.Flayn) { fs = new Flayn(flags); ((Flayn)fs).LoadPatterns(); foreach (var gamedir in flags.GameDirs) { fs.AddDataFS(gamedir); } } else if (flags.Leonhart) { fs = new Leonhart(flags); foreach (var gamedir in flags.GameDirs) { fs.AddDataFS(gamedir); } } else if (flags.Mitsunari) { fs = new Mitsunari(flags); foreach (var gamedir in flags.GameDirs) { fs.AddDataFS(gamedir); } } else if (flags.Nyotengu) { fs = new Nyotengu(flags); foreach (var rdb in flags.GameDirs.SelectMany(gamedir => Directory.GetFiles(gamedir, "*.rdb"))) { fs.AddDataFS(rdb); } ((Nyotengu)fs).LoadExtList(); } else if (flags.Zhao) // yep it's identical, but filenames are suffixed with .hash // so it would try to load RDB BINs in normal installs since those are named .rdb.bin { fs = new Nyotengu(flags); foreach (var rdb in flags.GameDirs.SelectMany(gamedir => Directory.GetFiles(gamedir, "*.rdb.*"))) { fs.AddDataFS(rdb); } ((Nyotengu)fs).LoadExtList(); } else if (flags.Reisalin) { fs = new Reisalin(flags); foreach (var gamedir in flags.GameDirs.SelectMany(gameDir => Directory.GetFiles(gameDir, "*.pak"))) { fs.AddDataFS(gamedir); } } else if (flags.Yshtola) { YshtolaSettings?settings = flags.GameId switch { "DissidiaNT" => new YshtolaDissidiaSettings(), "VenusVacation" => new YshtolaVenusVacationSettings(), _ => default }; if (settings == default) { Logger.Error("Cethleann", $"No decryption settings found for {flags.GameId}!"); return; } fs = new Yshtola(flags, settings); var yshtola = (Yshtola)fs; yshtola.Root = flags.GameDirs.ToArray(); foreach (var tableName in settings.TableNames) { fs.AddDataFS(tableName); } if (!Directory.Exists(flags.OutputDirectory)) { Directory.CreateDirectory(flags.OutputDirectory); } for (var index = 0; index < yshtola.Tables.Count; index++) { var table = yshtola.Tables[index]; var type = Path.GetDirectoryName(yshtola.Settings.TableNames[index]); var name = $"manifest-{type ?? "COMMON"}.{flags.GameId.ToLower()}"; File.WriteAllBytes(Path.Combine(flags.OutputDirectory, name), table.Buffer.ToArray()); } if (flags.YshtolaManifestOnly) { return; } } if (fs == null) { Logger.Error("Cethleann", "No FS specified! Prove --flayn, --reisalin, --leonhart, --mitsunari, --nyotengu, or --yshtola!"); return; } if (!flags.NoFilelist) { fs.LoadFileList(flags.FileList); } if (flags.NyotenguGeneratedFileList && fs is Nyotengu nyotengu) { nyotengu.SaveGeneratedFileList(flags.FileList); return; } for (var index = 0; index < fs.EntryCount; index++) { try { var data = fs.ReadEntry(index).Span; var dt = data.GetDataType(); var ext = UnbundlerLogic.GetExtension(data); var filepath = fs.GetFilename(index, ext, dt) ?? $"{index}.{ext}"; while (filepath.StartsWith("\\") || filepath.StartsWith("/")) { filepath = filepath.Substring(1); } if (flags.Reisalin && filepath.EndsWith(".gz", StringComparison.InvariantCultureIgnoreCase)) { if (data[4] == 0x78) { data = StreamCompression.Decompress(data, new CompressionOptions { Length = -1, Type = DataCompression.Deflate }); } filepath = filepath.Substring(0, filepath.Length - 3); } var pathBase = $@"{flags.OutputDirectory}\{filepath}"; UnbundlerLogic.TryExtractBlob(pathBase, data, false, flags, false); } catch (Exception e) { Logger.Error("Cethleann", e); #if DEBUG throw; #endif } } fs.Dispose(); }
/// <summary> /// Opens (or keeps) connection for receiving instrument profiles from server. /// </summary> private void Download() { var webRequest = URLInputStream.OpenConnection(address); webRequest.Headers.Add(Constants.LIVE_PROP_KEY, Constants.LIVE_PROP_REQUEST_YES); if (LastModified != DateTime.MinValue && !supportsLive && webRequest.GetType() == typeof(HttpWebRequest)) { ((HttpWebRequest)webRequest).IfModifiedSince = lastModified; } try { lock (webResponseLocker) { webResponse = webRequest.GetResponse(); } try { var isFileStream = webResponse.GetType() == typeof(FileWebResponse); DateTime time; if (isFileStream) { var fileUri = new Uri(address); time = File.GetLastWriteTime(fileUri.AbsolutePath); } else { URLInputStream.CheckConnectionResponseCode(webResponse); time = ((HttpWebResponse)webResponse).LastModified; supportsLive = Constants.LIVE_PROP_RESPONSE.Equals(webResponse.Headers.Get(Constants.LIVE_PROP_KEY)); } if (time == LastModified) { return; // nothing changed } MakeConnected(); using (var inputStream = webResponse.GetResponseStream()) { var compress = isFileStream ? StreamCompression.DetectCompressionByExtension(new Uri(address)) : StreamCompression.DetectCompressionByMimeType(webResponse.ContentType); using (var decompressedIn = compress.Decompress(inputStream)) { Process(decompressedIn); // Update timestamp only after first successful processing LastModified = time; } } } finally { lock (webResponseLocker) { webResponse = null; } } } catch (WebException we) { using (var webResponse = we.Response) { if (webResponse != null && webResponse.GetType() == typeof(HttpWebResponse) && ((HttpWebResponse)webResponse).StatusCode == HttpStatusCode.NotModified) { return; // not modified } } throw; } }